NastyDiaper
NastyDiaper

Reputation: 2558

Reduce array of arrays and remove null from Javascript data

I am having difficulty "compressing" the results of my grammar by stripping out null values and embedded arrays using Javascript. I am using the Nearley grammar checker which can run JS functions after a sentence is matched. Unfortunately you get the results of the full parse as a series of arrays. The following is an example of the output

[
   [
      [
         [
            [
               [
                  [ [ 'climb'], [ [ null, 'to' ] ] ],
                  [ [ null, [ 'alt' ] ] ],
                  [ 332, [ null, [ 'km' ] ] ]
               ]
            ],
            [ null ]
         ]
      ]
   ]
]

I would like to remove all those null values and possibly "compress" all those arrays to something of the form:

[
   [ 'climb', 'to' ],
   [ 'alt', 332, 'km' ]
]

Or something similar. I have tried using various filter methods without success.

Upvotes: 2

Views: 467

Answers (4)

Sunil Kumar
Sunil Kumar

Reputation: 420

let resArr = [];
  const findLoc = (arr, loc = []) => {
    arr.map((d, i) => {
      if (Array.isArray(d)) {
        findLoc(d, [ ...loc, i ]);
      } else {
        if (d !== null) {
          // console.log(d, loc);
          resArr.push([...loc, d])
        }
      }
    })
}

  const a = [
     [
        [
           [
              [
                 [
                    [ [ 'climb'], [ [ null, 'to' ] ] ],
                    [ [ null, [ 'alt' ] ] ],
                    [ 332, [ null, [ 'km' ] ] ],
                    [ 56, [ null, null, [ [ [8] ] ] ] ]
                 ]
              ],
              [ null ]
           ]
        ]
     ]
  ];
  findLoc(a);
  let finalIndex = [...resArr.reverse()[0]];
  finalIndex.splice(finalIndex.length -1 , 1);
  finalIndex = resArr[0].indexOf(Math.max(...finalIndex));
  const finalObj = {};
  resArr.forEach((d) => {
    finalObj[d[finalIndex]] = finalObj[d[finalIndex]] ? [...finalObj[d[finalIndex]], d[d.length -1]] : [d[d.length -1]]
  });
  console.log(Object.values(finalObj));
  
  // [ [ "to", "climb" ], [ "alt" ], [ "km", 332 ], [ 8, 56 ] ]

change the input and test,

using matrix logic we can active this

Upvotes: 0

54ka
54ka

Reputation: 3589

One line solution:

1.Convert to string 2.Split to flat array 3. Remove empty values

Example:

var arr = [
    [
        [
            [
                [
                    [
                        [['climb'], [[null, 'to']]],
                        [[null, ['alt']]],
                        [332, [null, ['km']]]
                    ]
                ],
                [null]
            ]
        ]
    ]
];



var res = arr.toString().split(",").filter(item => item);


console.log(res);

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386560

You could filter an map with the same approach and flat all arrays.

const
    filter = array => array.flatMap(v => Array.isArray(v)
        ? filter(v)
        : v === null
            ? []
            : v
    ),
    array = [[[[[[[['climb'], [[null, 'to']]], [[null, ['alt']]], [332, [null, ['km']]]]], [null]]]]],
    result = filter(array);

console.log(result);

An even shorter approach

const
    filter = array => array
        .flat(Infinity)
        .filter(v => v !== null),
    array = [[[[[[[['climb'], [[null, 'to']]], [[null, ['alt']]], [332, [null, ['km']]]]], [null]]]]],
    result = filter(array);

console.log(result);

Upvotes: 2

Peter Seliger
Peter Seliger

Reputation: 13376

Really?.. how about ['climb', 'to', 'alt', 332, 'km'] then? – Peter Seliger

That's wonderful. Some sort of logical grouping would be preferable but hey if not...

...

const sample = [[[[
  [[
    [ [ 'climb'], [ [ null, 'to' ] ] ],
    [ [ null, [ 'alt' ] ] ],
    [ 332, [ null, [ 'km' ] ] ]
  ]],
  [ null ]
]]]];

function flatOut(list, item) {
  if (Array.isArray(item)) {
    item = item.reduce(flatOut, []);
  }
  return list.concat(item);
}
const result = sample
  .reduce(flatOut, [])
  .filter(elm => (elm != null)); // non strict equality
  //...in order to skip both values, undefined and null.

console.log('result :', result);

Upvotes: 2

Related Questions