0

I am trying to write a function in JavaScript that takes an array as input and returns an array where similar elements are grouped in a sub-array. The function takes an array as input and returns an array as output.

For example, when I input groupfunction([1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20]), it should return [[1, 1, 1, 1], [2, 2, 2], 4, 5, 10, [20, 20], 391, 392, 591]. Instead, however, the function outputs [[1, 1, 1, 1], 2, [4, 4, 4], [591, 591], 392, 391, 5, 10, 20] for some reason. What can I use to group similar elements in an array into sub-arrays?

I found the following questions helpful and based my code on the answers contained within:

const findnumberofinstances = (array, element) => { // This function finds how many times a specific element occurs in an array
    let numberoftimes = 0;
    const functionisequal = (input1) => {if(input1 === element) {return true}
    else {return false}};
    const indexofelement = array.findIndex(functionisequal);
    while(array.includes(element) === true) {
        array.find(functionisequal);
        numberoftimes += 1;
        array.splice(indexofelement, 1);
    }
    return numberoftimes;
}

const finduniquevalues = (arr) => { // This function reduces an array to only have unique values.
    const map = [];
    for (let value of arr) {
        if (map.indexOf(value) === -1) {
            map.push(value);
        }
    }
    return map;
};

const removeElementsWithValue = (array, val) => { // This function removes specific values from an array
    var i = array.length;
    while (i--) {
        if (array[i] === val) {
            array.splice(i, 1);
        }
    }
    return array;
}

const removezeroes = (array) => {return removeElementsWithValue(array, 0)} // This function removes zeroes from an array

const repeatelement = (elem, n) => { // This function repeats an element, effectively multiplying an array of one value [value] by n so that value occurs n times.
    var arr = [];

    for (var i = 0; i < n; i++) {
        arr = arr.concat(elem);
    };

    return arr;
};

const findnumberofeachelement = (array) => {let blank = []; // This function finds how many of each element is in an array.
    let arraycopy = array.concat([]);
    let sortedArray = array.slice().sort();
    let arraycopysorted = arraycopy.slice().sort();
    for(element of arraycopysorted){let num = findnumberofinstances(sortedArray, element);
        blank.push(num);
    }
    return removezeroes(blank);
}

const groupfunction = (array) => { // This function groups elements that are identical into sub-arrays only if there are more than one of the elements.
    let sum = [];
    let unique = finduniquevalues(array);
    let blank = [];
    let number = findnumberofeachelement(array);
    for(let i=0; i< unique.length; i++) {
        if(number[i] > 1) {
            sum = repeatelement(unique[i], number[i])
            blank.push(sum);
        }
        else {
            sum = unique[i]
            blank.push(sum)
        }

        sum = []
    }
    return blank
}

console.log(groupfunction([1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20])) // This should return [[1, 1, 1, 1], [2, 2, 2], 4, 5, 10, [20, 20], 391, 392, 591].
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131

3 Answers3

1

You can use array#reduce to group your array on each value in an object accumulator.

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

console.log(groupfunction([1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Hassan Imam
  • 21,956
  • 5
  • 41
  • 51
0

There you go. It is not simple, but I should be correct.

function groupUp(array) {
    array.sort(function(a, b){return a - b})
    const map = new Map()
    const order = []
    array.forEach(e => {
        if (map.has(e)) {
            map.get(e).push(e)
        } else {
            map.set(e, [e])
            order.push(e)
        }
    })

    const final = []

    order.forEach(e => {
        const group = map.get(e)
        if (group.length == 1) {
            final.push(group[0])
        } else {
            final.push(group)
        }
    })

    return final
}

console.log(groupUp([1,2,4,591,392,391,2,5,10,2,1,1,1,20,20]))
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jakub Dóka
  • 2,477
  • 1
  • 7
  • 12
0

const a = [1,2,3,3,5,1, 10, 9, 10];

const b = a.reduce((acc,e ) => {
  const item = acc.find(i =>  i === e); // find item in array;

  if (item ){ // if we found item;
    const index = acc.indexOf(item);
    acc.splice(index, 1, [item, item]) // convert item to array
  } else {

    let inserted = false; // we'll push item into array or subarray   
    acc.forEach(item => {
      if (item instanceof Array && item === e){
        item.push(e);  // append item to subarray
        inserted = true;
      }
    }) 
    if (!inserted) acc.push(e); // append as item;

  }
  return acc; 
}, [] /* initial array */) 


console.log(JSON.stringify(b))
Daniil Loban
  • 4,165
  • 1
  • 14
  • 20