按照索引数组对对象数组进行排序

5
我尝试按键数组对对象数组进行排序。我搜索了类似的问题,但没有找到能帮助我的答案。
示例:
const data = [
 { label: 'String'},
 { label: 'Number'},
 { label: 'Boolean'},
 { label: 'Array'}
]

const order = [2, 3]

期望的结果:

const data = [
 { label: 'Boolean'},
 { label: 'Array'},
 { label: 'String'},
 { label: 'Number'}
]

我所面临的问题是:

  • order 数组可能与 data 数组长度不同,不在 order 中的项必须排在底部
  • data 对象没有一个帮助排序的 order 键,排序将由数组对象键位置进行

我尝试过但未成功的方法:

data.sort((a, b) => {
 const aIndex = data.indexOf(a);
 const bIndex = data.indexOf(b);

 if(aIndex !== -1) return -1;
 if(bIndex !== -1) return 1;
 
 return order.indexOf(aIndex) - order.indexOf(bIndex);
})

3
[2,3] 对输出结果有什么影响?您展示的输出结果似乎只是按字母数字顺序排序。 - Rory McCrossan
1
order数组中,我存储了我想要排序的对象的初始位置和我想要放置该对象的新位置。标签字符串只是一个例子,它可以是任何文本。 - Florin D
需要就地排序吗?还是返回一个已排序的副本可以接受? - Robby Cornelissen
4个回答

4
您可以使用一个Set来按需映射数据,代码如下:

const data = [
 { label: 'String'},
 { label: 'Number'},
 { label: 'Boolean'},
 { label: 'Array'}
]

const order = [2, 3];

const out = [...new Set([...order.map(i => data[i]), ...data])];

console.log(out);


我的错误在于我只关注了排序方法。你的解决方案看起来非常“干净”。谢谢! - Florin D
在这种情况下进行排序是不必要且不优的,你只需要转换一些已知数据即可。 - n--

1

不要使用排序,而是采用两步直接算法:

  1. 遍历 order 列表,并将相应的 data 项提取到新列表中(即排序后的列表)。在 data 中替换提取的值为 undefined
  2. 遍历 data,并将每个不是 undefined 的项附加到排序后的列表中。

const data = [
 { label: 'Test 3'},
 { label: 'Test 4'},
 { label: 'Test 1'},
 { label: 'Test 2'}
];

const order = [2, 3, 1, 5];


// Create a working copy of `data` (to not modify `data`)
const work = [...data];

// The sorted list
const sorted = [];

// Step 1
// Run through `order` and move the items from `work` to `sorted` in the provided order
order.forEach((index) => {
  const item = data[index];
  // There is nothing to do if `index` is an invalid index (or `data` does not contain anything at that position)
  if (item !== undefined) {
    sorted.push(item);
    work[index] = undefined;
  }
});

// Step 2
// Move the remaining items (they are not mentioned in `order`)
work.forEach((item) => {
  // Ignore the items that were moved on the first step
  if (item !== undefined) {
    sorted.push(item);
  }
});

// Cleanup
delete work;

// Check the output visually
console.log(sorted);


1

order中提取元素,然后添加那些不在order中的元素:

const data = [
    { label: 'String'},
    { label: 'Number'},
    { label: 'Boolean'},
    { label: 'Array'}
]

const order = [2, 3]

result = [
    ...order.map(i => data[i]),
    ...data.filter((_, i) => !order.includes(i)),
]

console.log(result)


1

我非常喜欢@n--的方法。然而,如果某个值在数组中出现多次,它将遇到困难。当我们使用data的索引而不是值构建Set时,这些问题可以非常容易地解决:

const data = [
 { label: 'String'},
 { label: 'Number'},
 { label: 'Boolean'},
 { label: 'Array'},
 { label: 'String'}
];
const order = [2, 3];
const out = [...new Set([...order,...data.keys()])].map(i=>data[i]);

console.log(out);


同意,这是一个可能存在于有缺陷的应用程序中的边缘情况。但通常,在列表中不希望出现同一对象的多个引用,这可能会导致更多的困难,因此在这种情况下 Set 的行为很容易成为一个有用的功能。 - n--
没错,@n--!我忽略了一个事实,就是我的示例在你原来的Set方法中仍然有效。我使用了不同的对象。然而,在更广泛的意义上,特别是当数组包含基元而不是对象时,上述问题可能会发生。 - Carsten Massmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接