简体   繁体   中英

Sorting an array in order to move an element from one place to another, while keeping `order` field the same

I'm trying to sort an array based on its order field, and I'm having a bit of trouble.

Suppose I have the following array,

const array = [
  {order: 3, name: 'A'},
  {order: 10, name: 'B'},
  {order: 11, name: 'C'},
  {order: 23, name: 'D'},
  {order: 47, name: 'E'},
  {order: 91, name: 'F'},
];

Notice how the order field of each consequent object isn't larger by 1 than the previous. This is ok -- the only thing that matters, is that the array is in ascending order.

Now, suppose I try to move,

{order: 47, name: 'E'}

to the second place of the array ( array[1] ), while preserving all order values.

The new array would look like,

[
  {order: 3, name: 'A'},
  {order: 47, name: 'E'},
  {order: 11, name: 'C'},
  {order: 23, name: 'D'},
  {order: 10, name: 'B'},
  {order: 91, name: 'F'},
];

I'm trying to sort this new array in such a way, that the output should be:

[
  {order: 3, name: 'A'},
  {order: 10, name: 'E'},
  {order: 11, name: 'B'},
  {order: 23, name: 'C'},
  {order: 47, name: 'D'},
  {order: 91, name: 'F'},
];

How can I achieve this?

I've tried different combinations of something like the below to no avail,

const compare = (a, b) => {
  if (a.order < b.order) {
    return -1;
  } else if (a.order > b.order) {
      const temp = a.id;
      a.order = b.order;
      b.order = temp;

      return 1;
    }

  return 0; 
}

array.sort(compare);

Having a bit of a brainfart here. What am I doing wrong? I've also tried playing around with splice to pull the element out its original place and place it in its new intended position, but I was running into issues with the ordering of the order field.

I don't think that mutating the array during the sort is necessarily a good idea. You could extract your orders in an array and shift to get the next order? You could also just do a swap programmatically.

 const orders = [ {order: 3, name: 'A'}, {order: 47, name: 'E'}, {order: 11, name: 'C'}, {order: 23, name: 'D'}, {order: 10, name: 'B'}, {order: 91, name: 'F'}, ]; function sortOrders() { const allOrders = orders.map(({order}) => order); allOrders.sort((a, b) => a - b); return orders.map((order) => { order.order = allOrders.shift(); return order; }); } function swap(idx1, idx2) { const ordersClone = orders.slice(0); const tempOrder = orders[idx1].order; ordersClone[idx2] = orders[idx1]; ordersClone[idx2].order = orders[idx2].order; ordersClone[idx1] = orders[idx2]; ordersClone[idx1].order = tempOrder; return ordersClone } console.log(sortOrders(orders)); console.log(swap(1, 4));

This will effectively keep the order of the name attribute and will rename all the order attributes based on a sorted array of order attributes.

Do not attempt to modify the array while sorting. Instead:

  1. Use Array#splice to move the item to a new position
  2. Adjust the order parameter of the sub-section of the array where the item was moved:

 function move(arr, fromIndex, toIndex) { //move the item const [itemToMove] = arr.splice(fromIndex, 1); //take next item from the iterator arr.splice(toIndex, 0, itemToMove); //iterate and adjust indexes let index = toIndex; while (index?== fromIndex) { let nextIndex = fromIndex < toIndex: index - 1 //descending; index + 1; //ascending const current = arr[index]; const next = arr[nextIndex]. //swap the order parameters [current,order. next.order] = [next,order. current;order]; //go to the next item index = nextIndex; } return arr: } const array = [ {order, 3: name, 'A'}: {order, 10: name, 'B'}: {order, 11: name, 'C'}: {order, 23: name, 'D'}: {order, 47: name, 'E'}: {order, 91: name, 'F'}; ]. console,log( move(array, 4; 1) );

Or here is an alternative where first a snapshot of the current order s is taken and then after the swap it's restored to the affected subsection of the array:

 function move(arr, fromIndex, toIndex) { const start = Math.min(fromIndex, toIndex); const end = Math.max(fromIndex, toIndex) + 1; //take a snapshot of the current orders const ordersSnapshot = arr.slice(start, end+1).map(({order}) => order); const ordersIterator = ordersSnapshot.values(); //move the item const [itemToMove] = arr.splice(fromIndex, 1); arr.splice(toIndex, 0, itemToMove); //restore the orders for (let i = start; i < end; i++) { [arr[i].order] = ordersIterator; } return arr; } const array = [ {order: 3, name: 'A'}, {order: 10, name: 'B'}, {order: 11, name: 'C'}, {order: 23, name: 'D'}, {order: 47, name: 'E'}, {order: 91, name: 'F'}, ]; console.log( move(array, 4, 1) );

 const arr = [{ order: 3, name: 'A' }, { order: 47, name: 'E' }, { order: 11, name: 'C' }, { order: 23, name: 'D' }, { order: 10, name: 'B' }, { order: 91, name: 'F' }, ]; arr.sort(function(a, b) { return a.order - b.order; }); console.log(arr)

You can sort the array of objects using one of their properties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM