按自定义顺序对对象数组进行排序

19

我有一个对象数组,其中每个对象都有一个名为“CODE”的属性。

[
  {
   ID: 168,
   NAME: "First name",
   CODE: "AD"
  },
  {
   ID: 167,
   NAME: "Second name",
   CODE: "CC"
  },
  {
   ID: 169,
   NAME: "Third name",
   CODE: "CCM"
  },
  {
   ID: 170,
   NAME: "Fourth name",
   CODE: "CR"
  },
]

如何按照自定义顺序对数组进行排序,例如:

var item_order = ["CCM","CR","AD","CC"];

一直尝试各种方法都没有成功。请帮忙。


1
无法理解排序的顺序。 - brk
你是说你想使用变量item_order作为数组来进行比较以确定顺序吗? - Woodrow
5个回答

39
你可以使用函数sort与函数indexOf一起使用。

var array = [  {   ID: 168,   NAME: "First name",   CODE: "AD"  },  {   ID: 167,   NAME: "Second name",   CODE: "CC"  },  {   ID: 169,   NAME: "Third name",   CODE: "CCM"  },  {   ID: 170,   NAME: "Fourth name",   CODE: "CR"  }],
    item_order = ["CCM","CR","AD","CC"];

array.sort((a, b) => item_order.indexOf(a.CODE) - item_order.indexOf(b.CODE));

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }


是的,但要注意@NinaScholz和我在答案中提到的大数组问题。 - Scott Sauyet
@ScottSauyet 是的,但那超出了范围。 - Ele
谢谢你的回答。我想根据item_order特别地按CODE属性对数组进行排序。 - newb1849
@newb1849 是的,这个答案提供了你需要的内容。 - Ele
我们知道这是否超出范围吗?我假设数组可能包含许多具有相同“CODE”值的元素,但这可能是错误的。我无法从问题本身中判断。对于大型数组,将调用indexOf O(n * log n)次。如果数组很小,甚至与排序数组具有相同的元素计数,则显然没有理由使用除此解决方案以外的任何东西。我当然不是在暗示它有什么问题;我只想指出它的局限性。 - Scott Sauyet

12

对于大型数组,建议使用对象来表示索引。

var array = [{ ID: 168, NAME: "First name", CODE: "AD" }, { ID: 167, NAME: "Second name", CODE: "CC" }, { ID: 169, NAME: "Third name", CODE: "CCM" }, { ID: 170, NAME: "Fourth name", CODE: "CR" }],
    item_order = ["CCM", "CR", "AD", "CC"],
    order = item_order.reduce((r, k, v) => Object.assign(r, { [k]: v }), {});

array.sort((a, b) => order[a.CODE] - order[b.CODE]);

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }


3
如果您经常需要执行此类操作,可以编写一个小工具来帮助:

const array = [{ ID: 168, NAME: "First name", CODE: "AD" }, { ID: 167, NAME: "Second name", CODE: "CC" }, { ID: 169, NAME: "Third name", CODE: "CCM" }, { ID: 170, NAME: "Fourth name", CODE: "CR" },{ ID: 166, NAME: "Fifth name", CODE: "CCM" }, { ID: 171, NAME: "Sixth name", CODE: "XXX" }, { ID: 172, NAME: "Seventh name", CODE: "CR" }]

const sortOn = (prop, list) => {
  const order = list.reduce((obj, key, idx) => Object.assign(obj, { [key]: idx + 1}), {});
  const getVal = item => order[item[prop]] || Infinity
  
  return (a, b) => getVal(a) - getVal(b)
}

array.sort(sortOn('CODE', ["CCM", "CR", "AD", "CC"]))
console.log(array)

< p> order 对象与 Nina Scholz 建议的对象非常相似。 之所以使用idx + 1而不是idx,是为了简化下一行的代码。该行使用 Infinity 作为一种方法,以使键值未定义或不在排序列表中的内容排序到末尾。 如果要将它们放在开头,则可以使用 0 或 -Infinity 。

@Mariusz:今天我会稍微改一下,用Object.fromEntries/map替换reduce/Object.assign部分。但基本思路非常有用。 - Scott Sauyet

1
你将使用 array.sort(customSort),其中:

function customSort(a,b)
{
    a = item_order.indexOf(a.CODE);
    b = item_order.indexOf(b.CODE);

    return a - b;
}

1

var array = [
  {
   ID: 168,
   NAME: "First name",
   CODE: "AD"
  },
  {
   ID: 167,
   NAME: "Second name",
   CODE: "CC"
  },
  {
   ID: 169,
   NAME: "Third name",
   CODE: "CCM"
  },
  {
   ID: 170,
   NAME: "Fourth name",
   CODE: "CR"
  },
];

var sortOrder =  ["CCM","CR","AD","CC"];

var sorted = array.sort((a, b) => sortOrder.indexOf(a.CODE) - sortOrder.indexOf(a.CODE));

console.log(sorted);


这是错误的!应该是var sorted = array.sort((a, b) => sortOrder.indexOf(a.CODE) - sortOrder.indexOf(b.CODE)); - Richard Zilahi

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