I have an array with numbers. I would like to put the numbers in order and create new array with duplicats in the same array(array in array). Can someone please help me step by step. I would really like to understand

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

// I want to create this [[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591]

const sortArray = arr.sort(function(a, b) {
        return a - b;
    });

7 Answers

5
briosheje On Best Solutions

You can extract unique values using Set, then sort them (because sorting an array of arrays is more complex), then use array.reduce to acquire all the items in the original array and push either the single value if unique, otherwise the array of values (not sure why you need that, but still..)

Further documentation reference:

Working code below:

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

// I want to create this [[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591]

console.log([...new Set(arr)].sort((a,b) => a - b).reduce((accumulator, next) => {
 const filtered = arr.filter(i => i === next);
  return accumulator.push(filtered.length === 1 ? filtered[0] : filtered), accumulator
}, []));

0
Katherine R On

Although there are other approaches, whenever I need to parse unique values from an array in this way, I will create an object with the object's properties representing the groupings of array values

{ 1: [1, 1, 1], 2: [2 , 2, 2], 4: [4], 5: [5] ...}

Then you can use a native object method to get all keys or values from the object if you need to (or if your end goal is different, you can use the object however it is needed)

Object.keys(obj)
// or
Object.values(obj)

For your case, it would look like

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

const obj = arr.reduce((accum, val) => {
    accum[val] = accum[val] || [];
    accum[val].push(val);
    return accum;
}, {});

const finalArr = Object.values(obj).map(val => val.length > 1 ? val : val[0]);
console.log(finalArr);
0
brk On

You can use reduce and then Array.fill. Here the reduce will create an object like this

{
  "1": 4,
  "2": 3,
  "4": 1,
  "5": 1,
  "10": 1,
  "20": 2,
  "391": 1,
  "392": 1,
  "591": 1
}

which mean there are 4 1s, 3 2s and so on. Then you can use array fill after iterating this object. The array fill syntax is arr.fill(value[, start[, end]])

So in our case we will case new Array(k[keys]).fill(+keys, 0, k[keys]) is creating a new array of length 4,3 so on except for 1 and from 0th index it is filling with the key

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

let k = arr.reduce(function(acc, curr) {
  if (curr in acc) {
    acc[curr] += 1;
  } else {
    acc[curr] = 1
  }

  return acc;
}, {});

let grouped = [];
for (let keys in k) {
  if (k[keys] !== 1) {
    grouped.push(new Array(k[keys]).fill(+keys, 0))
  } else {
    grouped.push(+keys)
  }
}
console.log(grouped)

0
Alex G On

You can count the occurrences and then use that object to create your final array.

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

const count = arr.reduce((acc, val) => {

  acc[val] = acc[val] + 1 || 1;

  return acc;
}, {});

const result = Object
  .keys(count)
  .sort((a, b) => a - b)
  .map((key) => count[key] === 1 ? +key : Array.from({ length: count[key] }).fill(+key));

console.log(result);

0
Ashish On

You can do this thing in ways. But if you want to achieve in best way, you must avoid n square loops.
So can create a dictionary of count of values. And loop over the keys of the object in sorted order.

Using Array.reduce to create object of count of array elemnts. and Array.fill to fil an array with same values.

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

   //Dictionary with count of each values in array
const arrCountObj = arr.reduce((acc, el) => {
  if (acc[el]) {
    acc[el] += 1
  } else {
    acc[el] = 1
  }
  return acc
}, {})
console.log(arrCountObj)
   //Looping over sorted dictionary keys to create array based on condition
var out = Object.keys(arrCountObj).sort((a, b) => a - b).map(x => arrCountObj[x] > 1 ? new Array(arrCountObj[x]).fill(+x) : arrCountObj[x])

console.log(out)

Time Complexity: O(nlogn)

1
Nina Scholz On

You could sort the array and have a look to the last two items and the actual item.

[   1,   1,   1,   1,   2,   2,   2,   4,   5,  10,  20,  20, 391, 392, 591] array
                   a    b    c                                               variables
                             ^                                               actual item

Then check if the last item b and the actual item c is unequal and return a new array with the the old items and the actual item.

If the item before the last item a and the actual item is unequal, it should be an array for the last item in the result set and the actual item.

Otherwise push the actual item to the nested last array of the result set.

var array = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20],
    result = array
        .sort((a, b) => a - b)
        .reduce((r, c, i, { [i - 2]: a, [i - 1]: b }) => {
             if (b !== c) return [...r, c];
             if (a !== c) return r.pop(), [...r, [b, c]];
             r[r.length - 1].push(c);
             return r;
        }, []);

console.log(result);

0
Andy On

You could:

1) iterate through the array an build a frequency map of the the numbers

2) grab and sort the frequency map key in ascending order

3) build a new array from the information in the frequency map

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

const obj = arr.reduce((acc, c) => {
  return acc[c] = (acc[c] || 0) + 1, acc;
}, {});

// {"1":4,"2":3,"4":1,"5":1,"10":1,"20":2,"391":1,"392":1,"591":1}

const keys = Object.keys(obj).sort((a, b) => a - b).map(Number);

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

const out = keys.map((key) => {
  return obj[key] > 1 ? Array(obj[key]).fill(key) : key;
});

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

console.log(JSON.stringify(out));