2

I'm attempting to create subarrays within an array that contains groupings of like numbers. I'm coding in JavaScript.

My array is [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];

I've sorted the array so its numbers are in order, I figured it would be easier to work with.Below is a visual of what I want to accomplish.

Example:

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

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

Thank you to anyone able to help!

2
  • I don't understand why this question has been closed. It seems pretty straightforward to me. Commented Apr 5, 2020 at 0:45
  • 1
    @KevinAmiranoff it might have been not clear in the beginning. I voted to re-open. Commented Apr 5, 2020 at 0:45

5 Answers 5

3

The solution

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

let temp = {};
array.forEach( el => {
  if(temp[el] != null){
    temp[el].push(el)
  }else{
    temp[el] = [el]
  }
})

let output = Object.values(temp).map(e=>e[1]?e:e[0]);

console.log(output)

The Funny version :)

__={};
[ 1, 1, 1, 1, 2, 2, 2, 4, 5, 10, 20, 20, 391, 392, 591 ]
.forEach(_=>__[_]?__[_].push(_):__[_]=[_]);
__=Object.values(__).map(_=>_[1]?_:_[0]);
console.log(__);

Disclaimer: this snippet is here only for entertainment purposes, I strongly discourage you to use it in production

Sign up to request clarification or add additional context in comments.

4 Comments

I think you have an issue as single values are inserted into sub-arrays as well.
@KevinAmiranoff thats right 👍, solved; in a non-readable way, just for some fun :)
Ahah I am still struggling trying to find my own solution :)
@KevinAmiranoff check the fun section bro :)
2

sort() the numbers, reduce() to arrays, and map() to take the numbers that occur a single time out of their array:

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

let sort = arr.sort((a,b) => a - b)

let res = sort.reduce((acc,cur) => {
    if(acc[acc.length-1] && cur === acc[acc.length-1][0]){
        acc[acc.length-1].push(cur)
    }else{
        acc.push([cur])
    }
    return acc
},[]).map(el => el.length === 1 ? el[0] : el)

console.log(res)

Comments

2

this can be achieved using an object as a holder and then the Object.values function to get the different entries.

so, this process will create something like

just an example
{
    1: [1,1,1,1],
    2: [2,2,2]
    5: 5,
    etc.....
}

and then executing Object.values will give us the right values from each key, returning something like

[
    [1,1,1,1],
    [2,2,2],
    5,
    etc....
]

you have a working example here, read carefully, we had to add that extra if inside, just to get the values alone, otherwise it would get something like [5].

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

// we create an object using as key the values.
const reducerFN = (accumulation, value) => {
  const hasKey = accumulation[value];
  // if the key exist, we have our array/value, lets push.
  if (hasKey) {
    // if it is an array, we push the value
    if (Array.isArray(accumulation[value])) {
      accumulation[value].push(value)
    } else {
      // otherwise, we initialize the array with 2 values(the new one and the old one)
      accumulation[value] = [value, value]
    }
  } else {
    // just initialize the value.
    accumulation[value] = value
  }
  return accumulation
}

// use reduce with the reducerFN
const pre_result = array.reduce(reducerFN, {});

// we have our map easy to read.
// now lets get the values, and it is as easy as this:
const result = Object.values(pre_result)

console.log(result);

Comments

2

Since you have sorted the array, I think just reduce is sufficient:

let array = [ 1, 1, 1, 1, 2, 2, 2, 4, 5, 10, 20, 20, 391, 392, 591 ];
let output = array.reduce((accumulator, currentValue) => {
  if(accumulator.length > 0) {
    let last = accumulator.length - 1;
    if(Array.isArray(accumulator[last])){
      if(-1 !== accumulator[last].indexOf(currentValue)){
        accumulator[last].push(currentValue)
        return accumulator;
      }
    }else if(currentValue === accumulator[last]){
      accumulator[last] = [accumulator[last], currentValue]
      return accumulator;
    }
  }
  accumulator.push(currentValue);
  return accumulator;
}, []);
console.log(output);

2 Comments

I'm confused by your use of accumulator. Why was the accumulator initialed as an empty array? Thank you for your help, I really appreciate you taking the time to solve this!
@user13224810 You're welcome. Accumulator will be the output eventually, so it should be an array at last. If there is not initial value, the first element of the array will be the first accumulator, which is 1, with type of Number. Although I can change it to array manually, it will be more convenient to use an initial empty array, to make every element of the array share the same process.
2

You can group each element into an array using .reduce() and a Map. Whenever you see a number in your array, you can check the map and see whether it is a key. If it is a key, then that number has already previously been seen. The value for each key (ie: number) can hold the frequency of each number and how many times it has been seen. If the number isn't in the Map, you can add it and set its frequency to 1. Once you have created the map using .reduce(), you can use Array.from(), by using the map as the first argument and adding a mapping function as the second argument. The second mapping function gets called for every key-value pair in the map. If the frequency value is greater than one, you can create an array from these values, if it is equal to one then you can return the number itself:

const arr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
const res = Array.from(
  arr.sort((a, b) => a - b)
    .reduce((map, n) => map.set(n, (map.get(n) || 0) + 1), new Map), 
  ([n, freq]) => freq > 1 ? Array(freq).fill(n) : n
);
console.log(res);

You could also set the values to arrays, and then concatenate to the array preexisting array. When you map, you can return the array or the first value in the array:

const arr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
const res = Array.from(
  arr.sort((a, b) => a - b)
    .reduce((map, n) => map.set(n, (map.get(n) || []).concat(n)), new Map).values(), 
  g_arr => g_arr.length > 1 ? g_arr : g_arr.shift()
);
console.log(res);

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.