1

I have a list of N elements with an array of three colors like this:

[
  { id: 1, colors: ['Red', 'Blue', 'White'] },
  { id: 2, colors: ['Red', 'Blue', 'Blue'] },
  { id: 3, colors: ['Red', 'Red', 'White'] },
  { id: 4, colors: ['Red', 'Red', 'Red'] }
]

And I would like to sort them based on this priority order, for example:

[Red,Red,Red]
[Red,Red,X]
[Red,X,Red]
[Red,X,X]
[X,Red,Red]
[X,Red,X]
[X,X,Red]

Where the 'X' indicates any other color that is not the one I indicate, in this example is 'Red'.

So an expected output, for this example would be:

[
  { id: 1, colors: ['Red', 'Red', 'Red'] },
  { id: 2, colors: ['Red', 'Red', 'White'] },
  { id: 3, colors: ['Red', 'Blue', 'White'] },
  { id: 4, colors: ['Red', 'Blue', 'Blue'] }
]

Any idea on how to approach this?

I tried finding the duplicates and sorting the parent array based on the colors, but I need to take into consideration the priority order.

elements.sort((a, b) => {
  const colorDupsA = findDuplicates(a.colors);
  const colorDupsB = findDuplicates(b.colors);
  return colorDupsB.length - colorDupsA.length;
});
2
  • 1
    if you don't need any sorting between different possible X values (ie you don't care if Blue comes before or after Yellow), then interestingly, you'll notice that your priority illustration is already in alphabetical order, so all you'd need to do is generate that string for all the objects in your array and sort based on that string Commented Dec 30, 2020 at 16:26
  • Ok, I added which would be an expected output for this case. The priority illustration can be for any color I specify, so not sure how it's in alphabetical order. The colors array don't need to be modified, just the order of the parent array. Commented Dec 30, 2020 at 16:42

4 Answers 4

1

Or, using an index array srt you can do it in the following way:

const arr=[
  {id: 1,colors: ['Red', 'Blue', 'White']},
  {id: 1,colors: ['Red', 'Blue', 'Blue']},
  {id: 1,colors: ['Red', 'Red', 'White']},
  {id: 1,colors: ['Red', 'Red', 'Red']}];
const srt=arr.map((e,i)=>[i,e.colors.map(c=>c=="Red"?"1":"0").join("")])
console.log(srt.sort((a,b)=>b[1]-a[1]).map(([i])=>arr[i]));

You can even reduce it to a one-liner:

arr.map((e,i)=>[i,e.colors.map(c=>c=="Red"?"1":"0").join("")])
   .sort((a,b)=>b[1]-a[1]).map(([i])=>arr[i])
Sign up to request clarification or add additional context in comments.

Comments

0

In the sort method, Calculate the value for each object based on permutation order and compare values.

const data = [
  { colors: ["Blue", "Blue", "Red"] },
  { colors: ["Blue", "Red", "White"] },
  { colors: ["Blue", "Blue", "White"] },
  { colors: ["Red", "Blue", "White"] },
  { colors: ["Red", "Blue", "Blue"] },
  { colors: ["Red", "Red", "White"] },
  { colors: ["Red", "Red", "Red"] },
];

const getValue = (obj) =>
  obj.colors.reduce((acc, cur) => +(cur === "Red") + acc * 10, 0);
  
data.sort((a, b) => getValue(b) - getValue(a));

console.log(data);

Comments

0

So you need to loop over the arrays and figure out if the one is red and the other. If they both or or both are not, then you move to the next and check.

const data = [
  { colors: ['Blue', 'Blue', 'Red'] },
  { colors: ['Blue', 'Red', 'White'] },
  { colors: ['Blue', 'Blue', 'White'] },
  { colors: ['Red', 'Blue', 'White'] },
  { colors: ['Red', 'Blue', 'Blue'] },
  { colors: ['Red', 'Red', 'White'] },
  { colors: ['Red', 'Red', 'Red'] }
];


data.sort((a,b) => {
  const ac = a.colors;
  const bc = b.colors
  for (let i=0; i<ac.length; i++){
    const check = (ac[i] === bc[i]) || (ac[i] !== 'Red' && bc[i] !== 'Red');
    if (check) continue;
    return ac[i] === 'Red' ? -1 : 1;
  }
  return 0;
});

console.log(data);

If you have to do sorting based on the other colors, generating a "weighted value" for the array would be a way to go

const data = [
  { colors: ['Blue', 'Blue', 'Red'] },
  { colors: ['Blue', 'Red', 'White'] },
  { colors: ['Blue', 'Blue', 'White'] },
  { colors: ['Red', 'Blue', 'White'] },
  { colors: ['Red', 'Blue', 'Blue'] },
  { colors: ['Red', 'Red', 'White'] },
  { colors: ['Red', 'Red', 'Red'] }
];

const values = {
  Red: 3,
  Blue: 2,
  White: 1,
};

const weight = arr => +arr.map(c => values[c] || 0).reverse().join("");

data.sort((a, b) => weight(b.colors) - weight(a.colors));

console.log(data);

Comments

0

Here is a possible solution:

  1. Create a private function getColorScore to calculate the score of a colors array according to the occurrences of your color and its indices in it. This can be done using .reduce
  2. Sort the array of objects using this function, where the object with the greater score for its colors list, would be first. This is done using .sort

const arr = [
  { id: 1, colors: ['Red', 'Blue', 'White'] },
  { id: 1, colors: ['Red', 'Blue', 'Blue'] },
  { id: 1, colors: ['Red', 'Red', 'White'] },
  { id: 1, colors: ['Red', 'Red', 'Red'] }
];

const getColorScore = (colors, color) => colors.reduce((acc,item,index) => {
    acc += item===color ? colors.length-index : 0;
    return acc;
  }, 0);

const sortArrayByColor = (arr,color) =>
  arr.sort((a,b) => getColorScore(b.colors,color)-getColorScore(a.colors,color))

console.log( sortArrayByColor(arr,'Red') );

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.