Extract contiguous elements from an array in JavaScript I'm trying to extract contiguous elements from an outcome array and print their equivalent elements in a reference array. This is my test case:

it('should split into fragments', function() {
  let ranges = getRanges({
    reference: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
    outcome: [true, true, false, false, true, false, false, true]
  })
  expect(ranges).to.eql([
    ['a b', true],
    ['c d', false],
    ['e', true],
    ['f g', false],
    ['h', true]
  ])
})


This works, but I'm wondering if there is a more elegant way of doing this:

function getRanges({reference, outcome}) {
  function withinBoundsAndSameOutcome(i, currentOutcome) {
    return i &lt; outcome.length &amp;&amp; outcome[i] == currentOutcome
  }
  let ranges = []
  for (let i = 0; i &lt; outcome.length; i++) {
    let range = [reference[i]]
    let currentOutcome = outcome[i]
    while (withinBoundsAndSameOutcome(i + 1, currentOutcome)) {
      i += 1
      range.push(reference[i])
    }
    ranges.push([range.join(' '), currentOutcome])
  }
  return ranges
}
Remarks on the provided implementation:

The code is already well structured and easy to follow along, even though it is not immediately clear what you are actually trying to accomplish.


The chosen function, argument and variable names could be more concise. Example:

ranges.push([range.join(' '), currentOutcome]);


Here, you push a 'range' and an 'outcome' into an array of 'ranges'. So 'range' actually represents two different things which should probably have their own names:


A subsequence of reference
A pair consisting of a joined 'range' as per 1. and an 'outcome'.

Moving the while loop condition to its own function with somewhat self-documenting name withinBoundsAndSameOutcome is an interesting idea. However, it disrupts the visual parsing of your code as the reader has to jump back to the definition in order to gain a complete understanding of that loop condition. As the condition itself is pretty standard, I'd prefer inlining it.
Terminating statements with semicolons instead of relying on JavaScript's semicolon auto-insertion is the norm as it avoids some ambiguities.


Alternative implementation:


  I'm wondering if there is a more elegant way of doing this:
  
  I'm trying to extract contiguous elements from an outcome array and
  print their equivalent elements in a reference array.


So you already identified two tasks:


Partition an array into intervals of equal values
Map those partitions to reference values


I recommend to follow this 'natural' structure and solve these two tasks independently.

Generator functions are a great tool for untangling your seemingly interwoven code and pushing individual functionality into their own reusable, testable functions. They are especially useful when you are not interested in storing intermediate results but rather want to directly process (e.g. print) them: 



// Partition array into intervals of equal values:
function* partitions(array, start = 0, next = start + 1) {
  while (next &lt; array.length &amp;&amp; array[start] === array[next]) next++;
  if (next &lt;= array.length) {
    yield [start, next];
    yield* partitions(array, next);
  }
}

// Return reference strings for partitions of outcome:
function* ranges({reference, outcome}) {
  for (let [start, end] of partitions(outcome)) {
    yield [reference.slice(start, end).join(' '), outcome[start]];
  }
}

// Example:
let data = {
  reference: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
  outcome: [true, true, false, false, true, false, false, true]
};

for (let range of ranges(data)) {
  console.log(range);
}




But even without generators, your implementation could benefit from the suggested split.