【问题标题】:How to sort an array of objects with labels according to other array of labels?如何根据其他标签数组对带有标签的对象数组进行排序?
【发布时间】:2019-10-29 11:25:51
【问题描述】:

我想对一个带有标签的对象数组进行排序,例如

var arrayToBeSorted = [{label: 'firstLabel', value: 123}, {label: 'secondLabel', value: 456}, {label: 'thirdLabel', value: 789}]

和一个标签数组作为基线,例如

var labels = ['secondLabel', 'thirdLabel', 'fourthLabel', 'firstLabel']

现在我想对我的第一个数组进行排序,以便其中的对象遵循第二个数组labels 中的标签顺序。

我知道带有自定义比较器的基本排序机制,例如

CustomComparator: function(a, b) {
  if (a[0].length > b[0].length) return -1;
  if (a[0].length < b[0].length) return 1;
  return 0;
}

但我不知道如何转换它。

在我的研究中,我发现this 解决方案是用 ruby​​ 编码的 stackoverflow,但我不知道 javascript 中是否有类似的选项。

感谢您的帮助,为此投入了相当多的时间。

【问题讨论】:

  • stackoverflow.com/q/13304543/10221765 并转换为对象数组。
  • Nina 指出了我刚刚修复的答案中的一个选项存在问题。 ping 你让你知道,因为你已经接受了我的回答,所以如果你使用了那个选项...... :-)

标签: javascript sorting


【解决方案1】:

有几种方法:

  1. 使用indexOf重复搜索labels数组

  2. 使用地图查找标签的索引更快

这是一个使用 indexOf 的示例(在 ES2015+ 中):

arrayToBeSorted.sort((a, b) => labels.indexOf(a.label) - labels.indexOf(b.label));

实时复制:

var arrayToBeSorted = [{label: 'firstLabel', value: 123}, {label: 'secondLabel', value: 456}, {label: 'thirdLabel', value: 789}];

var labels = ['secondLabel', 'thirdLabel', 'fourthLabel', 'firstLabel'];

arrayToBeSorted.sort((a, b) => labels.indexOf(a.label) - labels.indexOf(b.label));

console.log(arrayToBeSorted);

请注意,如果labels 中不存在标签,indexOf 将返回-1,这将使未知标签出现在结果的开头。如果您希望它们放在最后,请检查 -1 并将其替换为 Infinity

这是一个使用地图来加快查找这些索引的示例(在 ES2015+ 中):

const map = new Map(labels.map((label, index) => [label, index]));
arrayToBeSorted.sort((a, b) => {
    let aindex = map.get(a.label);
    if (aindex === null) {
        aindex = -1; // Or Infinity if you want them at the end
    }
    let bindex = map.get(b.label);
    if (bindex === null) {
        bindex = -1; // ""
    }
    return aindex - bindex;
});

实时复制:

var arrayToBeSorted = [{label: 'firstLabel', value: 123}, {label: 'secondLabel', value: 456}, {label: 'thirdLabel', value: 789}];

var labels = ['secondLabel', 'thirdLabel', 'fourthLabel', 'firstLabel'];

const map = new Map(labels.map((label, index) => [label, index]));
arrayToBeSorted.sort((a, b) => {
    let aindex = map.get(a.label);
    if (aindex === null) {
        aindex = -1; // Or Infinity if you want them at the end
    }
    let bindex = map.get(b.label);
    if (bindex === null) {
        bindex = -1; // ""
    }
    return aindex - bindex;
});

console.log(arrayToBeSorted);

这是为了清楚起见并避免在回调中多次查找标签。以地图中的第二个标签查找为代价可以更简洁:

const map = new Map(labels.map((label, index) => [label, index]));
arrayToBeSorted.sort((a, b) => {
    const aindex = map.has(a.label) ? map.get(a.label) : -1; // Or Infinity if you want them at the end
    const bindex = map.has(b.label) ? map.get(b.label) : -1; // "
    return aindex - bindex;
});

实时复制:

var arrayToBeSorted = [{label: 'firstLabel', value: 123}, {label: 'secondLabel', value: 456}, {label: 'thirdLabel', value: 789}];

var labels = ['secondLabel', 'thirdLabel', 'fourthLabel', 'firstLabel'];

const map = new Map(labels.map((label, index) => [label, index]));
arrayToBeSorted.sort((a, b) => {
    const aindex = map.has(a.label) ? map.get(a.label) : -1; // Or Infinity if you want them at the end
    const bindex = map.has(b.label) ? map.get(b.label) : -1; // "
    return aindex - bindex;
});

console.log(arrayToBeSorted);

甚至可以是:

const map = new Map(labels.map((label, index) => [label, index]));
arrayToBeSorted.sort((a, b) =>
    (map.has(a.label) ? map.get(a.label) : -1) - (map.has(b.label) ? map.get(b.label) : -1)
);

...但是对我来说,调试等时让生活变得太困难了。

【讨论】:

  • @NinaScholz - Gah,第二种方法中的 -1 是个坏主意,™ 谢谢。首先,您使用什么值并不重要。我的意思是要包含一个说明默认值的说明。我将修复 -1 问题并添加该注释,谢谢。
【解决方案2】:

您需要按第二个数组为值提供优先级。在这里,我们从第二个数组名称作为键和索引作为优先级构建一个 Map。所以你可以使用Mapdefault valuesort

var arrayToBeSorted = [{label: 'firstLabel', value: 123}, {label: 'secondLabel', value: 456}, {label: 'thirdLabel', value: 789}]
var labels = ['secondLabel', 'thirdLabel', 'fourthLabel', 'firstLabel']

let mapper = new Map(labels.map((v, i) => [v, i + 1]))

let final = arrayToBeSorted.sort((a, b) => {
  return (mapper.get(a.label) || Infinity) - (mapper.get(b.label) || Infinity)
})

console.log(final)

【讨论】:

    【解决方案3】:

    您可以创建自定义订单并通过它订购:

    var arrayToBeSorted = [
        {label: 'firstLabel', value: 123}, 
        {label: 'secondLabel', value: 456}, 
        {label: 'thirdLabel', value: 789}
    ];
    
    let order = { secondLabel: 1, thirdLabel: 2, fourthLabel: 3, firstLabel: 4 };
    
    arrayToBeSorted.sort((a, b) => {
      return order[a.label] - order[b.label];
    });
    
    console.log(arrayToBeSorted);

    【讨论】:

      【解决方案4】:

      直接使用sort-array

      const sortArray = require('sort-array')
      
      const arrayToBeSorted = [
        {label: 'firstLabel', value: 123},
        {label: 'secondLabel', value: 456},
        {label: 'thirdLabel', value: 789}
      ]
      
      sortArray(arrayToBeSorted, {
        by: 'label',
        order: 'labelOrder',
        customOrders: {
          labelOrder: ['secondLabel', 'thirdLabel', 'fourthLabel', 'firstLabel']
        }
      })
      
      console.log(arrayToBeSorted)
      

      打印此输出:

      [
        { label: 'secondLabel', value: 456 },
        { label: 'thirdLabel', value: 789 },
        { label: 'firstLabel', value: 123 }
      ]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多