Considering the JSON structure bellow, I need to be able to change the position of an item. The position can be changed only in increments of 1 (so +1 or -1).
Given the fact that I always send back to the API the entire JSON and that there can be a few hundreds items in the structure, is there a known algorithm to achieve this positions change fast?
The item is searched in the structure by its id.
For example I want to update the "position" of item with "id = 2" to "1". This step is easy because I can loop through the structure and find the element by id. But where I got stuck is the step where I need to update the other items accordingly.
I'm looking to implement this in PHP or Javascript.
{
"employees": {
"employee": [
{
"id": "1",
"firstName": "Tom",
"lastName": "Cruise",
"position": 1
},
{
"id": "2",
"firstName": "Maria",
"lastName": "Sharapova",
"position": 2
},
{
"id": "3",
"firstName": "Robert",
"lastName": "Downey Jr.",
"position": 3
}
]
}
}
If you want to change the position of an element from i
to j
, you need to change the positions of the elements of which position is between i
to j
.
var arr = [
{
"id": "1",
"firstName": "Tom",
"lastName": "Cruise",
"position": 1
},
{
"id": "2",
"firstName": "Maria",
"lastName": "Sharapova",
"position": 2
},
{
"id": "3",
"firstName": "Robert",
"lastName": "Downey Jr.",
"position": 3
}
]
function changePosition(from, to) {
var startValue;
var endValue;
for (var l = 0; l < arr.length; l++) {
if (arr[l].position == from) {
startValue = arr[l].position;
}
if (arr[l].position == to) {
endValue = arr[l].position;
}
}
var i = Math.min(startValue, endValue);
var j = Math.max(startValue, endValue);
var inc = from > to ? 1 : -1;
for (var k = 0; k < arr.length; k++) {
if (arr[k].position >= i && arr[k].position <= j) {
if (arr[k].position == from) {
arr[k].position = to;
} else {
arr[k].position += inc;
}
}
}
}
changePosition(3, 1);
console.log(arr);
</div>
Assuming that position
is always the array index + 1, you could do this in one sweep, for instance using the findIndex
array method.
Here is a function taking three arguments:
id
value of the entry that should movefunction moveId(obj, id, direction) {
const arr = obj.employees.employee;
const i = arr.findIndex((_, i) => i < arr.length - 1
&& arr[i+(direction === -1)].id === id);
if (i < 0) return; // No action. Either not found, or entry cannot move further.
arr.splice(i, 2, arr[i+1], arr[i]); // Swap the two elements...
arr[i].position = i+1; // ...and update their positions accordingly
arr[i+1].position = i+2;
}
// Example call
const obj = {"employees": {"employee": [{"id": "1","firstName": "Tom","lastName": "Cruise","position": 1},{"id": "2","firstName": "Maria","lastName": "Sharapova","position": 2},{"id": "3","firstName": "Robert","lastName": "Downey Jr.","position": 3}]}};
moveId(obj, "2", -1);
console.log(obj); // swapped & positions updated
</div>
Not completely sure I understand what you want to achieve, but what you could do, is create a new object, where the key is the position (create this object by iterating over the original, and manipulating the position value accordingly), and because objects are ordered by key, you will automatically end up with an ordered list of items, which you can convert back to it's original format.
Your object would look something like this:
{
1: { "id": "1", "firstName": "Tom", "lastName": "Cruise", "position": 1 },
2: { "id": "2", "firstName": "Maria", "lastName": "Sharapova", "position": 2 },
3: { "id": "3", "firstName": "Robert", "lastName": "Downey Jr.", "position": 3 }
}