Can someone help me with this algorithm of splitting arrays from some values?

Viewed 98

I am trying to automate my work and I am breaking a big array into smaller arrays like so:

function splitArray(arr, firstbreak, secondBreak, thirdBreak, fourthBreak) {
  var split1 = arr.slice(0, firstbreak);
  var split2 = arr.slice(firstbreak, firstbreak + secondBreak);
  var split3 = arr.slice(firstbreak + secondBreak, firstbreak + secondBreak + thirdBreak);
  var split4 = arr.slice(firstbreak + secondBreak + thirdBreak, firstbreak + secondBreak + thirdBreak + fourthBreak);

  console.log(split1); //[1,2,3]
  console.log(split2); //[4,5,6,7]
  console.log(split3); //[8]
  console.log(split4); //[9,10]
}


splitArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, 4, 3, 1, 2)

How can I automate this? I tried with a for loop but got a bit stuck I can't seeem to be able to get the recurring formula...

4 Answers

You could collect the lengths and map the part arrays.

function splitArray(array, ...lengths) {
    return lengths.map((i => l => array.slice(i, i += l))(0));
}

console.log(splitArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, 4, 3, 1, 2))
.as-console-wrapper { max-height: 100% !important; top: 0; }

The key generalizable step you are looking for is to feed the breakpoints themselves in as an array

This solves the specific challenge you had of how to automate (i.e. generalize) your existing code for variable numbers of breakpoints.

Below is one working example, that uses your approach in all other respects.

Reading how you use the breakpoints, they are more "lengths" than "breakpoints", so I have called them "lengths" in this code.

I've given two different calls to splitArray because the call you make in your example would not (with your code) produce the output listed in your code comments.

function splitArray(arr, lengths) {
  let pointer = 0;
  lengths.forEach(length => {
    console.log(arr.slice(pointer, pointer + length));
    pointer += length;
  })
}

splitArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 4, 3, 1, 2])

// And to produce the example output in your question:
splitArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [3, 4, 1, 2])

If must feed the breakpoints/lengths as separate input parameters rather than an array, you can use the Javascript ... operator to automatically gather them up into an array, like this:

function splitArray(arr, ...lengths)

However this only works in programming languages that have that facility, and would become a problem if you later needed to pass in two or more lists of numbers of variable length.

This is why I recommend passing the breakpoints/lengths as an array, namely avoiding painting yourself into a corner if your program later becomes more complex, or you need implement the algorithm in another language for some reason.

My try to split array based on dynamic breaks

let splitar = (ar,breaks) => {
   breaks.forEach(x=>{
       console.log(ar.splice(0,x));
   });
   console.log('remaining',ar);
}

let breaks = [4,3,5,1]
let ar = [11,23,43,1,2,4,12,6,8,34,23,51,12,5,123]

splitar(ar,breaks);

Result

[ 11, 23, 43, 1 ]
[ 2, 4, 12 ]
[ 6, 8, 34, 23, 51 ]
[ 12 ]
remaining [ 5, 123 ]

It looks like you are looking for an Array Distribution function...


    function distributeArray(source, ...dists){
       var results = [];
       var next = 0;
       for( var i = 0; i < dists.length; i++){
         results[i] = results[i] ? results[i] : [];
         for( var j = 0; j < dists[i]; j++){
            next < dists.length ? results[i][j] = source[next++] : null;
         }
       }
       return results;
    }

using map, and leveraging slice's return behavior, you could:


    function distributeArray(source, ...dists) {
        let pos = 0;
        return dists.map(function(span){ 
          return source.slice(pos, pos += span);
        });
    }

which could be expressed as a parameterized higher order immediately invoked function expression as:


   function distributeArray(source, ...dists) {
        return((results, n, j, i) => {
           for(i = 0; i < dists.length; i++){
             results[i] = results[i] ? results[i] : [];
             for(j = 0; j < dists[i]; j++) n < dists.length ? results[i][j] = source[n++] : null;
           }
           return results;
        })([], 0);
    }

which simplified with arrow functions, map and slice becomes:


    function distributeArray(source, ...dists) {
        return dists.map((p => s => source.slice(p, p += s))(0));
    }

function distributeArray(source, ...dists) {
  results = [];
  next = 0;
  end = source.length;

  dists.forEach(function(size) {
    if (next > end) {
      results.push([]);
    } else {
      results.push(source.slice(next, next += size));
    }
  });

  return results;
}

console.log(distributeArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, 4, 3, 1, 2));

Related