用于更新JSON响应中元素位置的最快算法[关闭]

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:

  • The object that should be mutated (in-place)
  • The id value of the entry that should move
  • The direction of the move: should be either 1 or -1.

function 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 }
}