7

As input, I receive two types of arrays of arrays made of x and y coordinates that represent polygon and multipolygon geometries.

array1 represents coordinates of a simple polygon geometry and array2 represent a multipolygon geometry:

var array1 = [[[0 , 0], [0, 1], [0 ,2]]]

var array2 = [[[[0, 0] , [0, 1], [0, 2]], [[1, 0], [1, 1], [1 ,2]]]]

Multipolygon geometry (array2) are represented by an array of arrays one level deeper than simple polygon geometry (array1).

I want to flatten those arrays in order to get those output:

   if input is array1 type : array1_out = [[0, 0, 0, 1, 0, 2]]

   if input is array2 type : array2_out = [[0, 0, 0, 1, 0, 2], [1, 0, 1, 1, 1, 2]]

My function is the following:

for (i=0; i < array_input.length; i++){
    var array_concat = array_input[i].reduce(function(a, b){
        return a.concat(b);
    });
}

With this function above, the output for array1 is correct but the output of array2 is the following:

[[[0, 0] ,[0, 1], [0, 2]], [1, 0], [1, 1], [1, 2]]]

Is there a function to deeply flatten those two types of arrays?

Edit: Performance really matter here as the arrays are really big

Below the Radar
  • 7,321
  • 11
  • 63
  • 142

2 Answers2

1

You can add a small wrapper for your function, that can check what type in input and a bit modify input

function getDeepLength(arr) {
  for (var i = 0, cur = arr; cur[0] instanceof Array; i++, cur = cur[0]);
  return i;
}

function Flatten(array_input) {
  var array_concat = [];
  for (i = 0; i < array_input.length; i++) {
    array_concat.push(array_input[i].reduce(function(a, b) {
      return a.concat(b);
    }));
  }
  return array_concat;
}

function Wrapper(arr) {
  var deep = getDeepLength(arr);
  var cur = arr;
  if (deep > 2) {
    for (var i = deep - 2; i > 0; i--, cur = cur[0]);
  }
  return Flatten(cur)
}

var array1 = [
  [
    [0, 0],
    [0, 1],
    [0, 2]
  ]
];

var array2 = [
  [
    [
      [0, 0],
      [0, 1],
      [0, 2]
    ],
    [
      [1, 0],
      [1, 1],
      [1, 2]
    ]
  ]
];

document.getElementById('r').innerHTML = "array1: " 
+ JSON.stringify(array1)+"<br/>"
+ "flat array1: "+JSON.stringify(Wrapper(array1))+"<br/>"
+ "array2: "+JSON.stringify(array2)+"<br/>"
+ "flat array2: "+JSON.stringify(Wrapper(array2));
<div id='r'></div>
Grundy
  • 13,356
  • 3
  • 35
  • 55
1

You can find a lot of helpful tools for manipulating arrays and collections in the Underscore and lodash libraries.

var arrays1 = [[[0 , 0], [0, 1], [0 ,2]]];
var array2 = [[[[0, 0] , [0, 1], [0, 2]], [[1, 0], [1, 1], [1 ,2]], ]];

var array1_out = flattenSimple(arrays1);
console.log(JSON.stringify(array1_out));

var array2_out = flattenMultiple(array2);
console.log(JSON.stringify(array2_out));

function flattenSimple(array_input) {    
    return _.flatten(array_input);
}

function flattenMultiple(array_input) {
    array_input = array_input[0];
    return array_input.map(function(a) {
        return _.flatten(a);
    });
}

Will produce the output you're looking for. I broke it into a flatten fn for each type, but you could use the same fn with a flag or more complex logic to know which type you're working with.

Fiddle

davidmdem
  • 3,763
  • 2
  • 30
  • 33