Filippo Rivolta
Filippo Rivolta

Reputation: 324

Using filter instead of foreach

I am currently trying to execute some operations after retrieving some data, the format I am trying to achieve is an array of strings: let cleanedData = ['foo', 'bar']

The data I receive could either be an array of objects or an array of arrays that could have empty arrays that needs to be filtered out. So for example I can receive either: let notCleanedData = [['foo'],[],[],['bar']] or this let notCleanedData = [{var: 'foo'}, {var: 'bar'}]

This is my code, it is working but I would like to improve it in a cleaner way or with ES6+ methods I have tried to use a filter function without success, any advice?

function filterInputData(notCleanedData) {
  let cleanedInputData = [];
  notCleanedData.forEach(input => {
    if (input.length > 0) {
      cleanedInputData.push(input)
    }
    if (input.var) {
      cleanedInputData.push(input.var)
    }
  });
  return cleanedInputData;
}

console.log(
  filterInputData([['foo'],[],[],['bar']]) 
)  
console.log(
  filterInputData([{var: 'foo'}, {var: 'bar'}])
)  

Upvotes: 3

Views: 595

Answers (5)

ganjim
ganjim

Reputation: 1416

This is a simple one-line solution that comes to my mind without using any libraries:

const clean = (data) => data.map(item => item.var ||  item[0]).filter(item => item)

I tried it on the test inputs you provided:

const clean = (data) => data.map(item => item.var ||  item[0]).filter(item => item)

console.log(
  clean([['foo'],[],[],['bar']]) 
)  
console.log(
  clean([{var: 'foo'}, {var: 'bar'}])
)

Upvotes: 2

Shimmy568
Shimmy568

Reputation: 503

In this situation you can use map to achieve what you want without foreach. Filter wont work since it can only remove elements from the list and not actually make any modifications to them.

function filterInputData(notCleanedData) {
    let cleanedInputData = notCleanedData.map((input) => {
        if (input.length > 0) {
            return input;
        }
        if (input.var) {
            return input.var;
        }
    }).filter(item => item !== undefined);
    return cleanedInputData;
}

Upvotes: 0

Samuel Goldenbaum
Samuel Goldenbaum

Reputation: 18919

I'd bring in lodash to help here.

You can use flattenDeep to clean and flatten and map to test if the data includes objects.

Example:

function clean(data) {
   return 
     _.chain(data)
       .flattenDeep()
       .map(x => {
    	  if (x.var) {
            return x.var;
          }
      
          return x;
       })
      .value();
}

console.log(
  clean([['foo'],[],[],['bar']]) 
)  
console.log(
  clean([{var: 'foo'}, {var: 'bar'}])
) 
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

Upvotes: 0

Shivratna Kumar
Shivratna Kumar

Reputation: 1311

Here is a much cleaner approach using reduce:-

// This function assumes that the array inside the array has single value and the object inside array has only one key called var
function filterInputData(notCleanedData) {
    return notCleanedData.reduce((acc, item) => {
        if (item.length) acc.push(item[0]);
        if (item.var) acc.push(item.var);
        return acc;
    }, [])
}

Hope you find this useful.

Upvotes: 0

ferhatelmas
ferhatelmas

Reputation: 3978

const input = [['foo'],[],[],['bar']]
const input2 = [{var: 'foo'}, {var: 'bar'}]

const clean = (data) => data && data[0].length // check type
    ? data.flat(1) // use new flat method if array
    : (data || []).map((e) => e.var) // map objects otherwise

Upvotes: 1

Related Questions