将选定的数组索引移动到指定位置

时间:2019-02-14 00:27:25

标签: javascript

我正在尝试根据选定的ID对选定数量的数组重新排序。例如,我有一个数组:

[ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 } ]

,并且选择的ID为1,2,4。正确的安排应为:

[ { id: 3 }, { id: 1 }, { id: 2 }, { id: 4 }, { id: 5 }] 

我设法使安排对一个选定的ID起作用,但是当选择多个ID时,它在不同的测试用例上失败。这些都假定与上面相同的输入。

输入1: [ 1, 2, 4 ],移至索引1

[ { id: 3 }, { id: 1 }, { id: 2 }, { id: 4 }, { id: 5 } ]

输入2: [ 1, 3, 4 ],移至索引1

[ { id: 2 }, { id: 1 }, { id: 3 }, { id: 4 }, { id: 5 } ]

输入3: [ 1, 3, 5 ],移至索引1

[ { id: 2 }, { id: 1 }, { id: 3 }, { id: 5 }, { id: 4 } ]

输入4: [ 1, 2 ],移至索引01

[ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 } ]

输入5: [ 4, 5 ],移至索引34

[ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 } ]
/**
 * Function to move array
 */
function array_move(arr, old_index, new_index) {
  if (new_index >= arr.length) {
    var k = new_index - arr.length + 1;
    while (k--) {
      arr.push(undefined);
    }
  }
  arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
};

/**
 * Function to find the index
 */
function findWithAttr(array, attr, value) {
  for (var i = 0; i < array.length; i += 1) {
    if (array[i][attr] === value) {
      return i;
    }
  }
  return -1;
}

/**
 * Move array to specified position
 */
function moveToSpecifiedInput(selectedImage, iMoveTo) {
  selectedImage.reverse();
  selectedImage.forEach(function(aData) {
    let old_index = findWithAttr(aImageData, 'id', aData);
    let new_index = iMoveTo - 1;

    array_move(aImageData, old_index, new_index);
  });
}

4 个答案:

答案 0 :(得分:1)

从数组中删除与ID匹配的元素,并将其放入新数组中。然后将新阵列拼接回原始阵列。

function move_array_elements(array, ids, new_index) {
  let extracted = [];
  ids.forEach(id => {
    let index = array.findIndex(el => el.id == id);
    if (index != -1) {
      extracted.push(array[index]);
      array.splice(index, 1);
    }
  });
  array.splice(new_index, 0, ...extracted);
  return array;
}

const orig_array = [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 } ];
console.log(move_array_elements(orig_array, [1, 2, 4], 1));

答案 1 :(得分:1)

通过评论中的澄清,我认为我理解您的问题。这就是我要解决的方法:

function sortArray(array, sortProp, sortValues, sortIndex) {
  const elemsBySortVal = array.reduce((obj, elem, idx) => {
    obj[elem[sortProp]] = idx;
    return obj;
  }, {});
  
  let sortedKeys = sortValues.map(val => elemsBySortVal[val]);
  let sortedItems = sortedKeys.map(key => array[key]);
  let remainingItems = array.filter((_, idx) => !sortedKeys.includes(idx));
  
  return [
    ...remainingItems.slice(0, sortIndex),
    ...sortedItems,
    ...remainingItems.slice(sortIndex),
  ];
}

console.log(sortArray(
  [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 } ],
  'id',
  [ 1, 2, 4 ],
  1,
));

此解决方案分为三个阶段:

阶段1:

这是最复杂的部分。在这里,我们接受您的输入array并针对输入索引创建一个排序值映射。最好通过示例显示:

输入(array):

[ { id: 1 }, { id: 3 }, { id: 5 }, { id: 2 }, { id: 4 } ]

输出(elemsBySortVal):

{
  1: 0,
  3: 1,
  5: 2,
  2: 3,
  4: 4,
}

阶段2:

现在,我们使用该映射来获取输入数组中作为排序值传递的值的索引:

输入(sortValues):

[ 1, 2, 4 ]

输出(sortedKeys):

[ 0, 3, 4 ]

然后将其映射到输入数组中的元素:

输入(sortedKeys):

[ 0, 3, 4 ]

输出(sortedItems):

[ { id: 1 }, { id: 2 }, { id: 4 } ]

最后,使用sortedKeys从输入数组中选择其余项,以排除已经排序的项:

remainingItems

[ { id: 3 }, { id: 5 } ]

请注意,即使删除了元素,第2阶段中的所有操作仍保持这些数组的顺序。

阶段3:

现在,我们将输出数组分为3部分:

  • 已排序部分之前的元素
  • 排序部分中的元素
  • 排序后的元素

使用slice作为切入点,从remainingItems sortIndex中切出{@ 1}},排序后的部分只是上一阶段的sortedItems

答案 2 :(得分:1)

您可以使用过滤器和接头 请检查评论

let arr=[{id:1}, {id:2}, {id:3}, {id:4}, {id:5}];
let selected=[1,2,4];
let move_2_index=1;

//filter out selected 
const selectedonly = arr.filter(a=>selected.includes(a.id));
//filter out not selected
const notselected = arr.filter(a=>!selected.includes(a.id));
//splice to insert selected on not selectd
notselected.splice(move_2_index, 0, selectedonly);
//flattern the array
final_array=notselected.flat();
console.log(final_array);

答案 3 :(得分:1)

使用null作为占位符

演示中的详细信息。

演示

let arr=[{id:1},{id:2},{id:3},{id:4},{id:5}];

Array.prototype.move = function(to, moveFrom) {
  // Make a copy of the original array
  let that = [...this];
  // Declare an empty array
  let moveTo = [];
  /*
  - Compare current index with the numbers in move array (offset)
  - Replace each match with a null as a placeholder so that the
    indexes of the array is still accurate.
  - Place each match into the empty array from previous step.
  */
  that.forEach(function(obj, idx, arr) {
    if (moveFrom.indexOf(idx +1) !== -1) {
      moveTo.push(arr.splice(idx, 1, null));
    }
  });
  // Remove all nulls
  that = that.filter(function(obj) {
    return obj !== null;
  });
  /*
  Insert the new moving array into the copied array at the index
  indicated in the first parameter.
  */
  that.splice(to, 0, moveTo.flat())
  return that.flat();
};

console.log(JSON.stringify(arr.move(1, [1, 3, 4])));
console.log(JSON.stringify(arr.move(0, [1, 2, 5])));
console.log(JSON.stringify(arr.move(3, [1, 2, 3])));
console.log(JSON.stringify(arr.move(1, [2, 5])));
console.log(JSON.stringify(arr.move(2, [1, 4])));