Home > Back-end >  Map and filter in one method?
Map and filter in one method?

Time:07-07

The following code processes a list of file paths and should return only the file names (without extension) of XML files. Currently I got to this:

const filteredFiles = files
  .map(f => f.match(/.*\/(.*)\.xml/)) // map to regex match with capture
  .filter(v => v)                     // non-matches returned null and will be filtered out here
  .map(m => m[1])                     // map out the regex capture

I find this code quite cumbersome. Is there no way to combine the matching and filtering in a more "efficient" way? And by "efficient" I mean code-readable-efficient and not time-efficient as the input array holds 100 values at most but most of the time between 10 and 20.

CodePudding user response:

This doesn't solve your need of mapping and filtering out the non matching values in one shot... but it makes one step easier by using the optional chaining operator ?.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

I also slightly changed the regex to allow the filename with no path specifed.

const files = [
  './path/to/filename_01.xml',
  'non_matching_value',
  './path/to/filename_02.xml',
  './path/to/filename_03.xml',
  './path/to/filename_04.xml',
  'filename_05.xml',
];

const filteredFiles = files
  .map(filename => filename.match(/^(.*\/)?(.*)\.xml/)?.[2])
  .filter(filename => filename);
  
console.log(filteredFiles);

CodePudding user response:

You can (ab)use flat map:

const filteredFiles = files.flatMap((f)=>{
  let match = f.match('...');
  if (match) {
      return [match[1]]
  } else {
      return []
  }
})

Not sure if it's actually better than the original though.

CodePudding user response:

Map and filter, otherwise known as reduce

const rx = /\/(.*)\.xml$/;

const filteredFiles = files.reduce((arr, f) => {
  const match = f.match(rx);
  return match ? [...arr, match[1]] : arr;
}, []);

CodePudding user response:

As I added in comment, you could use reduce method of array to achieve this in single iteration

Example

const regex = /\/(.*)\.xml$/;

const filteredFiles = files.reduce((r, f) => {
  const value = f.match(regex);
  if (value?.[1]) {
    return [...r, value[1]];//If matches found then return previous result   new value 
  }
  return r; // If not matches found then return previous result 
}, []);
  • Related