Generate striped blocks of indexes from an array

Tags: , ,



I have an array of n length and I want to generate a new array to act as a list of its indexes such that the indexes are “striped” into blocks. By “striping” I mean that we’ll move up the indexes from A-Z in an incremental fashion multiple times, retaining a patterned order.

For example, let’s say our array has 30 elements, indexes 0-29.

I want to be able to provide an integer to act as a factor that speaks to how “mixed up” I want the stripes to be; how many blocks I want the indexes reordering into.

Factor 1 (reorder the indexes into 1 block – obviously nothing happens)

[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29]

Factor 2 (reorder the indexes into 2 striped blocks)

[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,  1,3,5,7,9,11,13,15,17,19,21,23,25,27,29]

Factor 4 (reorder into 4 blocks)

[0,4,8,12,16,20,24,28,  1,5,9,13,17,21,25,29,  2,6,10,14,18,22,26,  3,7,11,15,19,23,27]

Factor 7

[0,7,14,21,28,  1,8,15,22,29,  2,9,16,23,  3,10,17,24,  4,11,18,25,  5,12,19,26,  6,13,20,27]

I don’t need to reorder the original array or even to produce this reordered list in full – I just need to loop over the existing array items and work out what position their index would put them in this theoretical reordered list.

The function should obviously work for an array of any length, and any block factor (as long as it’s an integer).

One key thing is that the block lengths will differ if n % f !== 0. Take our factor 4 list above, where we have two blocks of 8 indexes, and two blocks of 7 indexes. Similarly for the factor 7 list we get two blocks of 5 indexes and five blocks of 4 indexes.

We can work out several things quite quickly:

const perGroup                    = arrayLength / blockSize;
const largeGroupCount             = arrayLength % blockSize;
const indexThatSmallGroupsStartAt = largeGroupCount * Math.ceil(perGroup);

The question is – how do I get from this point to the finished function?

I’m part of the way there but I think I am hugely overcomplicating it and need a fresh pair of eyes (or brain) to help me finish it up!

for (i = 0; i < originalArray.length; i++){
  const groupSize = i < indexThatSmallGroupsStartAt ? Math.ceil(perGroup) : Math.floor(perGroup);

  const newIndex = ???
}

I’ve been trying to work out the group number at the moment and the position of the index in the new group but I’m not entirely sure either, or both, are necessary… (so this code is omitted from above)

The reason I’m “striping” the indexes in steadily increasing groups like this is because they’re going to be used to pull colours out of a spectrum. So you can imagine each group will traverse the whole spectrum of colours, but each element in any subsequent group will be shifted along the spectrum incrementally from where that element in the previous group would have been. I have an array of stuff I need a colour for and a function that already exists to pull an array of colours out of my spectrum. So I want to loop over each of the items in my original array and use the newIndex to get the colour from my colours array.

Answer

You can fill the array in order by just resetting the loop counter.

function stripe(length, blocks) {
  let a = new Array(length);
  let i = 0;
  for (let j = 0; i < length; ++j)
    for (let k = j; k < length; k += blocks)
      a[i++] = k;
  return a;
}

console.log(...stripe(30,1))
console.log(...stripe(30,2))
console.log(...stripe(30,4))
console.log(...stripe(30,7))


Source: stackoverflow