Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting an array, having all non-unique values nested

I am pretty new to javascript, and I was trying to build this function I found in a challenge. I have managed to solve this, but I feel like this is a very complicated way of doing things, what would be the fastest method here?

Basically answer(array) should transform this:

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

into this:

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

Here is my code so far:

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

const duplicates = arr =>
    arr.reduce((a, b) => ({ ...a,
        [b]: (a[b] || 0) + 1
    }), {})

array.sort((a, b) => a - b);
let array1 = duplicates(array);
var values = Object.values(array1);
var keys = Object.keys(array1);
var newArray = [];

for (let i = 0; i < keys.length; i++) {
    let tempArray = [];
    for (let j = 0; j < values[i]; j++) {
        tempArray.push(keys[i]);
    }
    newArray.push(tempArray);
}
console.log(newArray);

duplicates function comes from This post about finding duplicate values

like image 702
Marelons Avatar asked Sep 10 '20 07:09

Marelons


3 Answers

Have a look at this one-liner. Guess this is what you need.

Note that this isn't the most efficient way to to this - but guess it's beautyfull!

const array = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
const newArray = [...new Set(array)].sort((a, b) => a-b).map(e => new Array(array.filter( i => i === e).length).fill(e)).map(e => e.length === 1 ? e[0] : e);
console.log(newArray);

How this works:

  1. We're creating a set from the array with unique values [...new Set(array)]
  2. We're sorting the keys of the set .sort((a, b) => a-b)
  3. We're looping trought every value and calculating the occurrences of this value in the array .map(e => new Array(array.filter( i => i === e).length);
  4. In the last step we're filling the new Array with the amount of values and the value from the set from above .fill(e)
  5. We're iterating trought the array and make the entry flat if theres just a single value present .map(e => e.length === 1 ? e[0] : e)
like image 107
jns Avatar answered Nov 02 '22 23:11

jns


Your approach is good enough (fast). I made some modifications to use parseInt() on keys to convert the keys back to number from string. And also made sure that a single element is not nested (as your expected output in your OP.

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

const duplicates = arr =>
    arr.reduce((a, b) => ({ ...a,
        [b]: (a[b] || 0) + 1
    }), {})

array.sort((a, b) => a - b);
let array1 = duplicates(array);
var values = Object.values(array1);
var keys = Object.keys(array1);
var newArray = [];

for (let i = 0; i < keys.length; i++) {
    let tempArray = [];
    if (values[i] === 1) {
        newArray.push(parseInt(keys[i]));
    } else {
        newArray.push(Array(values[i]).fill(parseInt(keys[i])));
    }
}

console.log(newArray);
like image 27
Rahul Bhobe Avatar answered Nov 02 '22 22:11

Rahul Bhobe


Given the sorted array (ascending), you could have 2 variables, one storing the sorted unique array of element, one storing the occurrence of element in the array

After that, you map through the unique, if the occurence is greater than one, return an array filled by the element with the length of that element's occurrence, else just return that element

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

const sortedUnique = Array.from(new Set(sortedArray))
const occurences = sortedArray.reduce((acc, el) => {
  acc.set(el, (acc.get(el) || 0) + 1)
  return acc
}, new Map())

const res = sortedUnique.map((el) =>
  occurences.get(el) > 1 ? Array(occurences.get(el)).fill(el) : el
)

console.log(res)
like image 21
hgb123 Avatar answered Nov 02 '22 22:11

hgb123