1

I have a string of data which look like this

0E-11 GERBER CA 960350E-110.0215.500000000 0E-12 TEHAMA CA 960900E-11214.800000000

I want to convert this string into an array of arrays.

Please note that after every 4 elements this array should be divided into new array and the end result should look like this:

Desire Results:

this.tblData: Array(2)
            0: ["0E-11,"GERBER", "CA", "960350E-110.0215.500000000"]
            1:["0E-12", "TEHAMA", "CA" ,"960900E-11214.800000000"]

Thanks

Icepickle
  • 12,689
  • 3
  • 34
  • 48
ahmad735
  • 67
  • 9

3 Answers3

2

You can use the remainder operator and a forEach loop on that string to build an array of arrays, where each nested array is created every n steps:

var result = [];

"0E-11 GERBER CA 960350E-110.0215.500000000 0E-12 TEHAMA CA 960900E-11214.800000000".split(" ").forEach(function(element, index, array) {
  if( (index + 1) % 4 === 0) {
    result.push([
      array[index-3],
      array[index-2],
      array[index-1],
      array[index]
    ]);
  }
});

console.log(result);
worc
  • 3,654
  • 3
  • 31
  • 35
  • 1
    well, what happens if the string has instead 7 items or 9 after being splitted? – Icepickle Oct 12 '17 at 00:02
  • I would say that an edge case is actually input that matches the test scenario exactly :) – Icepickle Oct 12 '17 at 00:15
  • unless the data is well-formed, but for some reason inaccessible. then OP could assume the data is always some multiple of 4, and the edge case is malformed data. but even then you're talking about a single guard statement and some error logging, rather than a complex reworking of a basic forEach loop. – worc Oct 12 '17 at 00:18
  • 1
    the OP's data is clearly aligned to some consistent data, just look at the elements...the assumption is safe. – Rafael Oct 12 '17 at 00:28
  • @Rafael Sure it does exactly what the OP is asking for, but using arrays that are defined outside of a function is in my opinion code smell, then I like your solution a lot better, and yours will at least not loose values, just prefill an array with undefined. – Icepickle Oct 12 '17 at 00:40
  • @Icepickle ? there are no arrays defined outside of a function here. `result` is initialized, sure, but that's a requirement if you go down the `forEach` path since it doesn't do return values like the more modern `map` and `reduce` and `filter` and etc array functions. – worc Oct 12 '17 at 00:44
  • @Icepickle your concern is *valid*, I am just saying, the data is clearly aligned. If it was not, this answer, as you said, would miss data in the output. As far as the OP's question goes, this answer is also *valid*. – Rafael Oct 12 '17 at 00:44
  • @worc, surely, `forEach` is a function? – Icepickle Oct 12 '17 at 00:45
  • @Icepickle at least do me the courtesy of reading my whole comment. – worc Oct 12 '17 at 00:46
  • @worc, I am sorry, I don't see why this forEach would be better than a normal `for loop` as Rafaels, or a `for ... of`. I personally think that forEach as an array filler is code smell, as you mentioned there are more modern options, and if those wouldn't be available, the oldscool for loops would be just fine – Icepickle Oct 12 '17 at 00:49
  • @Icepickle `for loop` introduces another `var` that's unnecessary and is imperative rather than functional. `for ... of` is even smellier now that you're introducing syntax that's similar to--but functionally different from--`for ... in`. at least `forEach` is halfway to regular, old-fashioned functional streams in ES5/6 – worc Oct 12 '17 at 00:54
2

You can use reduce for such purposes

let result = "0E-11 GERBER CA 960350E-110.0215.500000000 0E-12 TEHAMA CA 960900E-11214.800000000"
  .split(" ") // split the string based on the spaces
  .reduce((current, item) => { 
    if (current[current.length - 1].length === 4) {
      // in case the result array has already 4 items in it
      // push in a new empty array
      current.push([]);
    }
    // add the item to the last array
    current[current.length - 1].push(item);
    // return the array, so it can either be returned or used for the next iteration
    return current;
  }, [ [] ]); // start value for current would be an array containing 1 array

console.log(result);

It starts by splitting your string by spaces, creating an array of the values, and then we can transform the result using the reduce function.

The reduce function will take the second parameter as a start value for the current argument, which will start as an array containing 1 empty array.

Inside the reducer it first check if the last item in the array has a length of 4, in case it does, add the next sub array to the array, and will then push the current item inside the last array.

The result will then be an array containing your arrays

Icepickle
  • 12,689
  • 3
  • 34
  • 48
2

There is no need to use modulus operator, simply increment the loop's counter by 4:

var original = [
    '0E-11',
    'GERBER',
    'CA',
    '960350E-110.0215.500000000',
    '0E-12',
    'TEHAMA',
    'CA',
    '960900E-11214.800000000'
];

var result = [];

for (var i = 0; i < original.length; i += 4) {
    result.push([
        original[i],
        original[i+1],
        original[i+2],
        original[i+3],
    ]);
}

console.log(result);

Output: [ [ '0E-11', 'GERBER', 'CA', '960350E-110.0215.500000000' ], [ '0E-12', 'TEHAMA', 'CA', '960900E-11214.800000000' ] ]

This assumes that the data is 4 element aligned.

Rafael
  • 7,605
  • 13
  • 31
  • 46
  • PS: the only reason I am against using a mod operator is because it introduces, expensive, branching into the code that doesn't need to be there. – Rafael Oct 12 '17 at 00:38