admin管理员组

文章数量:1404922

I want to sort an array of objects with labels, for example

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

and an array of labels as a baseline, for example

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

Now I want to sort my first array, so that the objects in it follow the order of labels in the second array labels.

I know basic sorting mechanism with custom parators like

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

but I have no idea on how to convert this.

In my research I found this solution on stackoverflow coded in ruby, but I don't know if there is a similar option in javascript.

I appreciate any help, invested quite some time on this.

I want to sort an array of objects with labels, for example

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

and an array of labels as a baseline, for example

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

Now I want to sort my first array, so that the objects in it follow the order of labels in the second array labels.

I know basic sorting mechanism with custom parators like

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

but I have no idea on how to convert this.

In my research I found this solution on stackoverflow coded in ruby, but I don't know if there is a similar option in javascript.

I appreciate any help, invested quite some time on this.

Share Improve this question asked Oct 29, 2019 at 11:25 MagelanMagelan 1893 silver badges14 bronze badges 2
  • 1 stackoverflow./q/13304543/10221765 and convert to array of objects. – Jack Bashford Commented Oct 29, 2019 at 11:28
  • Nina pointed out a problem with one of the options in my answer which I've fixed just now. Pinging you to let you know because you've accepted my answer and so if you used that option... :-) – T.J. Crowder Commented Oct 29, 2019 at 12:07
Add a ment  | 

4 Answers 4

Reset to default 3

You need to provide priority to values as per second array. here we are building a Map from second array name as key and index as priority. so you can use Map and default value and sort

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)

There are a couple of approaches:

  1. Using indexOf to repeatedly search the labels array

  2. Using a map so looking up the index of a label is quicker

Here's an example using indexOf (in ES2015+):

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

Live Copy:

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);

Note that indexOf will return -1 if the label doesn't exist in labels, which will make unknown labels appear at the beginning of the result. If you want them at the end instead, check for -1 and replace it with Infinity.

Here's an example using a map to speed up finding those indexes (in 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;
});

Live Copy:

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);

That's written for clarity and to avoid looking up the labels more than once in the callback. It can be more concise at the cost of a second label lookup in the map:

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;
});

Live Copy:

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);

It can even be:

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)
);

...but for me that's making life too difficult when debugging, etc.

You can create a custom order and order by it:

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);

Straight-forward using 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)

Prints this output:

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

本文标签: javascriptHow to sort an array of objects with labels according to other array of labelsStack Overflow