1

I have an array of objects such as

const myArrayOfColors = [
  { color: "red", number: 123 },
  { color: "red", number: 12 },
  { color: "green", number: 6 },
  { color: "blue", number: 7 },
  { color: "purple", number: 54 },
  { color: "green", number: 74 },
  { color: "blue", number: 41 },
  { color: "purple", number: 74 },
];

and I have an array of strings that I have to use as an order reference:

myOrder = ["red", "blue", "purple", "green"];

so I have to sort my objects array in order to comply with my order reference. I should have an output like this:

const myArrayOfColors = [
  { color: "red", number: 123 },
  { color: "blue", number: 7 },
  { color: "purple", number: 54 },
  { color: "green", number: 6 },
  { color: "red", number: 12 },
  { color: "blue", number: 41 },
  { color: "purple", number: 74 },
  { color: "green", number: 74 },
];
DecPK
  • 24,537
  • 6
  • 26
  • 42
  • 2
    What if there isn't enough elements to 'repeat' it? How do you know which color goes first (they have different numbers, signifying that they are each unique)? – Endothermic_Dragon May 20 '21 at 21:55

5 Answers5

1

Not sure this is best way, You can try this. So basically we run through the myArrayOfColors and then loop the order to find the order element, push it in result, then after Delete the item from main source (myArrayOfColors). Of course think about Time Complexity (assuming n³) here. (It's big )

const myArrayOfColors = [
  {color: 'red', number: 123},
  {color: 'red',  number: 12},
  {color:'green', number: 6},
  {color: 'blue', number: 7},
  {color:'purple', number:54},
  {color: 'green', number: 74},
  {color:'blue', number:41},
  {color: 'purple', number: 74},
]

const order = ['red', 'blue', 'purple', 'green']
const result = []

while(myArrayOfColors.length) {
 for (const o of order) {
    const colorIndex = myArrayOfColors.findIndex(e => e.color === o)
    if (colorIndex > -1) {
      result.push(myArrayOfColors[colorIndex])
      myArrayOfColors.splice(colorIndex, 1)
    }
  }
}

console.log(result)
Naren
  • 4,152
  • 3
  • 17
  • 28
0

Will work even for uneven groups that cannot be repeated.

I've added {color:'green',number:74} and {color:'red',number:74} to the end of myArrayOfColors:

const myArrayOfColors=[{color:'red',number:123},{color:'red',number:12},{color:'green',number:6},{color:'blue',number:7},{color:'purple',number:54},{color:'green',number:74},{color:'blue',number:41},{color:'purple',number:74},{color:'green',number:74}, {color:'red',number:74}]
const myOrder = ['red', 'blue', 'purple', 'green']

const res = []
let maxIterations = myArrayOfColors.length - myOrder.length

while (maxIterations--) {
  myOrder.forEach(e => {
    const c = myArrayOfColors.find(x => x.color === e) ?? {}
    c.color && res.push({...c})
    c.color = "-"
  })
}

console.log(res)
.as-console-wrapper { max-height: 100% !important; top: 0; }
ulou
  • 5,542
  • 5
  • 37
  • 47
0

Here's a simple way to make groups of unique elements, sorted according to a colors array:

function* createdOrderedGroups(items, colors) {
  items = [...items]
  let colorIndex = 0;
  while (items.length) {
    const index = items.findIndex(item => item.color === colors[colorIndex])
    if (index === -1) {
      throw new Error('Each color did not have the same number of assosiated items.');
    }
    yield items[index]
    items.splice(index, 1);

    colorIndex = (colorIndex + 1) % colors.length
  }
}

const myArrayOfColors = [
  {color: 'red', number: 123},
  {color: 'red',  number: 12},
  {color:'green', number: 6},
  {color: 'blue', number: 7},
  {color:'purple', number:54},
  {color: 'green', number: 74},
  {color:'blue', number:41},
  {color: 'purple', number: 74},
]

console.log([...createdOrderedGroups(myArrayOfColors, ['red', 'blue', 'purple', 'green'])])

Basically, we gradually remove items from the input array every time we find one with the color we're looking for, until there are no items left. We know which color we're looking for, by using a colorIndex variable, which starts at 0, and increments with each iteration until we get to the length of the color array, then it restarts at 0.

I'm using a generator here (the function* and yield stuff), but if that's new to you, you can instead just build a results array and return that whole array.

This solution will yield the first occurrence of each color from the input array, then it will yield the next occurrence it finds, and so forth, so the last item that has a color "red" will be one of the last elements yielded.

Scotty Jamison
  • 10,498
  • 2
  • 24
  • 30
0
  • You can easily achieve this result using first create a dict that contains the color and its number in the respective array.
  • calculate the max number of elements in respective color.
  • Now we know the max elements in an array, so we can loop over up to max and get color and its number from dict and store in the result array.`

const myArrayOfColors = [
  { color: "red", number: 123 },
  { color: "red", number: 12 },
  { color: "green", number: 6 },
  { color: "blue", number: 7 },
  { color: "purple", number: 54 },
  { color: "green", number: 74 },
  { color: "blue", number: 41 },
  { color: "purple", number: 74 },
  { color: "purple", number: 94 },
];

const myOrder = ["red", "blue", "purple", "green"];
let max = 0;
const dict = myArrayOfColors.reduce((acc, curr) => {
  const { color, number } = curr;
  if (acc[color]) acc[color].push(number);
  else acc[color] = [number];

  max = Math.max(max, acc[color].length);
  return acc;
}, {});

const result = [];
for (let i = 0; i < max; ++i) {
  myOrder.forEach((orderKey) => {
    const { [i]: val } = dict[orderKey];
    if (val) result.push({ color: orderKey, number: val });
  });
}

console.log(result);

Above snippet can also cover the case if any color repeat more than in myArrayOfColors, e.g purple repeat more than any color in array

const myArrayOfColors = [
  { color: "red", number: 123 },
  { color: "red", number: 12 },
  { color: "green", number: 6 },
  { color: "blue", number: 7 },
  { color: "purple", number: 54 },
  { color: "green", number: 74 },
  { color: "blue", number: 41 },
  { color: "purple", number: 74 },
  { color: "purple", number: 94 },
  { color: "purple", number: 84 },
  { color: "purple", number: 64 },
  { color: "purple", number: 54 },
];
DecPK
  • 24,537
  • 6
  • 26
  • 42
0

First build separate lists of the entries for each color, then use a custom comparator function for Array.prototype.sort().

const myArrayOfColors = [
  { color: "red", number: 123 },
  { color: "red", number: 12 },
  { color: "green", number: 6 },
  { color: "blue", number: 7 },
  { color: "purple", number: 54 },
  { color: "green", number: 74 },
  { color: "blue", number: 41 },
  { color: "purple", number: 74 },
];

myOrder = ["red", "blue", "purple", "green"];

myArraysPerColor = {};
for(const color of myOrder) {
  myArraysPerColor[color] = myArrayOfColors.filter(v=>v.color===color);
}

myArrayOfColors.sort((a,b) => 
  myArraysPerColor[a.color].indexOf(a)-myArraysPerColor[b.color].indexOf(b) ||
    myOrder.indexOf(a.color)-myOrder.indexOf(b.color)
);


console.log(myArrayOfColors);
loop
  • 825
  • 6
  • 15