Search code examples
javascriptarrayssortinggrouping

Jumble numbers in an array such that no two adjacent numbers are same using JavaScript


The idea it to basically not have repeated values in the array with similar values.

An example input array:

input = [1,2,2,2,2,3,4,5,6,7,8,9]

Expected output to be something like this:

desiredOutput = [1,2,3,2,4,2,5,2,6,2,7,8,9]

I have tried putting this in a for loop where it checks with the next item and if it is same, swaps the values. The problem is when I have continuous similar values.


Solution

  • This proposal features

    • count of elements and store it in an appropriate object,
    • check whether spread is possible (e.g. not here [1, 1, 1, 1, 3, 3]),
    • round robin with the elements, so
    • maximum distance between the same elements.

    How does it work?

    As example I take this array: [1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9]

    1. Build an object with the count of the elements, store it with the element as key.

      length = {
            "1": 1, "2": 4, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1, "8": 1, "9": 1
        }
      
    2. Select the property with the largest value: length[2] = 4
    3. Make a new array with the length of the previous value and fill it with empty arrays.

      output = [[], [], [], [], []]
      
    4. Check if a spreaded array is possible. If not, return.
    5. Set k to the key of the biggest value of a property.

      k = '2'
      
    6. If truthy, proceed. Otherwise go to 11.
    7. Set l to the value of length[k].

      l = 4
      
    8. Iterate over l and push k to the end of the array with the index of i % outputLength. Increase i.
    9. Delete property k.
    10. Proceed with 5.
    11. Return the flat output array.

      output   first  then continued
      array 0:     2     1     6
      array 1:     2     3     7
      array 2:     2     4     8
      array 3:     2     5     9
      
      return:      2  1  6  2  3  7  2  4  8  2  5  9
      distance     |        |        |        |       is equal  
      

    function spread(input) {
    
        function findMaxKey() {
            var max = 0, key;
            Object.keys(length).forEach(function (k) {
                if (length[k] > max) {
                    max = length[k];
                    key = k;
                }
            });
            return key;
        }
    
        var length = input.reduce(function (r, a) {
                r[a] = (r[a] || 0) + 1;
                return r;
            }, {}),
            i = 0, k = findMaxKey(), l,
            outputLength = length[k],
            output = Array.apply(Array, { length: outputLength }).map(function () { return []; });
    
        if (input.length - outputLength < outputLength - 1 ) {
            return; // no spread possible
        }
        while (k = findMaxKey()) {
            l = length[k];
            while (l--) {
                output[i % outputLength].push(k);
                i++;
            }
            delete length[k];
        }
        return output.reduce(function (r, a) { return r.concat(a) }, []);
    }
    console.log(spread([1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9]));
    console.log(spread([1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]));
    console.log(spread([1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]));
    console.log(spread([1, 1, 1, 1, 3, 3]));
    console.log(spread([1, 1, 3]));
    .as-console-wrapper { max-height: 100% !important; top: 0; }