Home > Blockchain >  Create an array of arrays of equivalent value
Create an array of arrays of equivalent value

Time:12-11

Here is the array:

const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20]

How can I achieve the following output?

output: // [[1, 1, 1, 1], [2, 2, 2], 4, 5, 10, [20, 20], 391, 392, 591]

Thanks for any help provided!

CodePudding user response:

This should work:

let array = [1, 1, 3, 2, 2, 5, 6, 4, 4];
array.sort((a, b) => a > b);

const result = [];
while(array.length > 0) {
  const firstEl = array[0];
  array.splice(0,1);
  const current = [firstEl];
  for(let x = 0; x < array.length; x  ) {
    if(array[x] == firstEl) {
      current.push(array[x]);
      array.splice(x, 1);
    }
  }
  result.push(current);
}

console.log(result);

CodePudding user response:

You can use a basic 'group by' and then flatten any arrays in the result with length 1.

const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];

const result = Object.values(arr
  .reduce((a, c) => {
    (a[c] ??= []).push(c);
    return a;
  }, {}))
  .map(a => a.length > 1 ? a : a[0]);

console.log(result);

The sorting that is seen in the output is a result of of javascript object property ordering which sorts integer keys first in ascending order, followed by non-integer keys in insertion order, see: Does JavaScript guarantee object property order?.

Edit

The same logic as the above can be implemented in a more transparent way using a for loop with explicit checks for properties instead of using nullish coallescing assignment (??=)

const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];

const grouped = {};

for (const element of arr) {
  if (grouped[element] === undefined) {
    grouped[element] = [];
  }

  grouped[element].push(element);
}

const result = Object.values(grouped)
  .map(a => a.length > 1 ? a : a[0]);

console.log(result);

CodePudding user response:

const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20]

result = [
    ...arr
        .sort((x, y) => x - y)
        .reduce(
            (m, x) => m.set(x, (m.get(x) ?? 0)   1),
            new Map
        )
].map(
    ([x, n]) => n === 1 ? x : Array(n).fill(x))

console.log(...result)

This produces what you're looking for, however that unpacking looks really ugly. How about a small utility function?

Object.prototype.tap = function (fn, ...args) {
    return fn(this, ...args)
}

//    

result = arr
    .sort((x, y) => x - y)
    .reduce(
        (m, x) => m.set(x, (m.get(x) ?? 0)   1),
        new Map
    )
    .tap(Array.from)
    .map(
        ([x, n]) => n === 1 ? x : Array(n).fill(x))
  • Related