Circular object Array returned when attempting to extract contiguous sub-arrays

Viewed 554

I want to find all contiguous sub-array from a given array.

For example, given array [1,2,3] I want to extract all contiguous sub-arrays:

[[1],[2],[3],[1,2],[1,2,3],[2,3]]

in any order.

I've attempted at a solution here: https://codepen.io/loganlee/pen/XWbPKeR?editors=0011

let a = [1, 2, 3];

let store = [];

a.forEach(
  (n, i) => {
    store.push([n]);
    let nested = [n];
    for (let index = i + 1; index < a.length; index++) {
      nested.push(a[index]);
      store.push(nested);
    }
  }
);

console.log(store);

I get log of store here:

[[1],[1,2,3],[circular object Array],[2],[2,3],[3]]

When I expect

[[1],[1,2],[1,2,3],[2],[2,3],[3]]

I'm not sure why "circular object Array" is present, and why [1,2] is missing.

Thank you very much!

4 Answers

You can do something like this.

  • First get the length of array. Based on array length we decide what should be final length of result array
  • Until index is less then length we capture individual element
  • Then we slice element from 0 to (i - (length-2)) This is to get element like [1,2], [1,2,3] in increasing range upto length of array
  • And finally slice elements from (i - (length-2))-length. This is to get elements like [2,3] etc.

function getSubsets(arr) {
  let length = arr.length
  let lengthMinus2 = length - 2
  if (length > 1) {
    let iterationCount = length + 2 * lengthMinus2 + 1
    return Array.from({
      length: iterationCount
    }, (_, i) => {
      if (i < length) {
        return arr[i]
      } else if ((i - lengthMinus2) <= length) {
        return arr.slice(0, i - lengthMinus2)
      } else {
        return arr.slice(i - lengthMinus2 - length)
      }
    })
  } else {
    return arr
  }
}

console.log(getSubsets([1, 2, 3]))
console.log(getSubsets([1, 2, 3, 4]))
console.log(getSubsets([1, 2, 3, 4, 5]))

Your code has an aliasing problem where multiple indices of store point to the same nested array. You can use store.push(nested.slice()); to avoid this by making a copy of nested on every push.

I think the function is a good candidate to be a generator:

function *contiguousSubarrays(a) {
  for (let i = 0; i < a.length; i++) {
    for (let j = i; j < a.length; j++) {
      yield a.slice(i, j + 1);
    }
  }
}

console.log([...contiguousSubarrays([1, 2, 3])]);

someone in irc posted this using slice:

let a = [1,2,3];

let store = [];

a.forEach(
  (n, start) => {
    for (let end = start + 1; end <= a.length; end++)
    {
      let nested = a.slice(start, end);
      store.push(nested);
    }
  }
);

console.log(store);

I think I misunderstood the question, sorry. This code does not answer the question, I leave because it may be useful to someone. This code is used for for "combinations without repetition":

var arr=[1,2,3,4,5];
var len=arr.length;
for(var i=(1<<len); --i;) {
  var ar=[];
  for(var k=0; k<len; ++k) { 
    if ((i>>k) & 1 ) { 
       ar.push(arr[k]); 
    }
  }
  console.log(ar);
}

This code answers the question. "sub-arrays":

var arr=[1,2,3,4,5];
var len=arr.length;
var ar=[];

for(var i=0; i<len; i++) {
  for(var k=1; k<(len+1); ++k) {
    if ((arr.slice(i,k)).length >0) {
       ar.push(arr.slice(i,k));
    }
}
}
console.log(ar);

Related