Matthias
Matthias

Reputation: 5764

Javascript array filter with conditional output / apply

I'm wondering, if there is a way to filter an array or stream and apply a function A to all matches and a function B to all non-matches in JavaScript. Here is some example code that explains it a bit more:

  // initial data
  var names = ['Matthias', 'Maria', 'Bob', 'Anton'];
  var namesWithM;
  var namesWithoutM;

  // gets only names starting with M, but not the others at the same time
  namesWithM = names.filter(name => name.startsWith('M'))

  // conditional lambda version
  namesWithM = [];
  namesWithoutM = [];
  names.forEach(name => name.startsWith('M') ? namesWithM.push(name) : namesWithoutM.push(name));


  // conditional classical version
  namesWithM = [];
  namesWithoutM = [];
  names.forEach(function(name) {
    if (name.startsWith('M'))
      namesWithM.push(name)
    else
      namesWithoutM.push(name);
  });

The very first version handles just the matches but uses filter and not forEach. Is there any way to use filter and apply a function for matches and non-matches at once? Something like this pseudo code:

names.filter(name.startsWith('M')).apply(namesWithM::push).or(namesWithoutM::push);

Upvotes: 1

Views: 40

Answers (3)

Józef Podlecki
Józef Podlecki

Reputation: 11283

I would use reduce to group data into 2 mentioned cases. I don't see any reason to use filter here

let names = ['Matthias', 'Maria', 'Bob', 'Anton'];

let [namesWithM, namesWithoutM] = names.reduce((acc, name) => {

  if (name.startsWith('M')) {
    acc[0] = [...(acc[0] || []), name]
    return acc;
  }

  acc[1] = [...(acc[1] || []), name]
  return acc;

}, [])

// simpler version
console.log(namesWithM, namesWithoutM);

let [namesWithM1, namesWithoutM1] = names.reduce((acc, name) => {
    const index = Number(!name.startsWith('M'));
    acc[index] = [...(acc[index] || []), name];
    return acc;
}, [])

console.log(namesWithM1, namesWithoutM1);

Upvotes: 1

brk
brk

Reputation: 50291

filter returns an array. So you can use this array to fill with name which either starts with M or not.

In the below example the filter is filling the array with name starts with M. In filter callback the name not starting with M are filled in another array

// initial data
var names = ['Matthias', 'Maria', 'Bob', 'Anton'];
var namesWithM;
var namesWithoutM = [];

namesWithM = names.filter((name) => {
  if (!name.startsWith('M')) {
    namesWithoutM.push(name)
  }
  return name.startsWith('M');
});

console.log(namesWithM, namesWithoutM);

Upvotes: 2

Alexandr Pashkevich
Alexandr Pashkevich

Reputation: 1

const names = ['Matthias', 'Maria', 'Bob', 'Anton'];
function A(item){
  console.log('filtered');
  console.log(item);
}
function B(item){
  console.log('not-ffiltered');
  console.log(item);
}
const filteredNames = names.filter(name => {
  const isValid = name.startsWith('M')
  if(isValid)
    A(name)
  else
    B(name)
  return isValid;
})

Upvotes: 0

Related Questions