Andrew Hill
Andrew Hill

Reputation: 2253

Is it possible to "filter" a Map by value in Typescript?

I am looking for a way to filter a map by value instead of key. I have a data set that is modeled as follows in my Angular application:

{
  "85d55e6b-f4bf-47bb-a988-78fdb9650ef0": {
    is_deleted: false,
    public_email: "[email protected]",
    id: "85d55e6b-f4bf-47bb-a988-78fdb9650ef0",
    modified_at: "2017-09-26T15:35:06.853492Z",
    social_url: "https://facebook.com/jamesbond007",
    event_id: "213b01de-da9e-4d19-8e9c-c0dae63e019c",
    visitor_id: "c3c232ff-1381-4776-a7f2-46c177ecde1c",
  },
}

The keys on these entries are the same as the id field on the entries values.

Given several of these entries, I would like to filter and return a new Map() that contains only those entries with a given event_id. Were this an array I would just do the following:

function example(eventId: string): Event[] {
  return array.filter((item: Event) => item.event_id === eventId);
}

Essentially, I am attempting to replicate the functionality of Array.prototype.map() - just on a Map instead of an Array.

I am willing to use Lodash if it will help achieve this in a more succinct way as it is already available in my project.

Upvotes: 30

Views: 95636

Answers (6)

trincot
trincot

Reputation: 350137

As of ECMAScript 2025 we have filter as an iterator helper method, so now you can avoid the creation of an intermediate array, and chain it directly on iterators returned by the entries, values or keys methods:

new Map(map.entries().filter(([key, item]) => item.event_id === eventId))

Demo:

const map = new Map([["Z", 1324], ["A", 1], ["B", 2], ["C", 3], ["D", -12345]]);
const filteredMap = new Map(map.entries().filter(([key, val]) => val < 10));
console.log(...filteredMap);

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 222354

If a key matters, and the result needs to be a new Map, it is:

new Map(
  [...map.entries()]
  .filter(([key, item]) => item.event_id === eventId)
)

A similar approach has been already suggested in other answers and listed for completeness.

If a key doesn't matter, a map can be converted to an array:

[...map.values()]
.filter((item: Event) => item.event_id === eventId);

Array.from(map.values()) should be used instead of [...map.values()], etc for TypeScript without downlevelIteration option.

Upvotes: 51

kewur
kewur

Reputation: 491

export class MapUtils {
  static filter<TKey, TValue>(map: Map<TKey, TValue>, filterFunction: (key: TKey, value: TValue) => boolean): Map<TKey, TValue> {
    const filteredMap: Map<TKey, TValue> = new Map<TKey, TValue>();
    
    map.forEach((value, key) => {
      if (filterFunction(key, value)) {
        filteredMap.set(key, value);
      }
    });
    
    return filteredMap;
  }
}

usage:

 const filteredMap = MapUtils.filter(map, (key, value) => value > 0)

Upvotes: 2

cs31415
cs31415

Reputation: 169

This one uses Object.entries to convert the map to an array, and Object.fromEntries to convert back to map.

let qs = {a:'A 1',b:null,c:'C 3'};
let qsfiltered = Object.fromEntries(
    Object.entries(qs).filter(([k,v]) => v !== null)
);

console.log(JSON.stringify(qsfiltered));

Upvotes: 0

Luc-Olivier
Luc-Olivier

Reputation: 3973

Here's a short syntax that keeps keys and values together:

const dict = new Map([["Z", 1324], ["A", 1], ["B", 2], ["C", 3], ["D", -12345]])

const filtered = [...dict.entries()].filter( it => it[1] < 10 ) 

// >  [ [ 'A', 1 ], [ 'B', 2 ], [ 'C', 3 ], [ 'D', -12345 ] ] 

Upvotes: 11

oreofeolurin
oreofeolurin

Reputation: 636

First you need to flatten the map, Then extract the contents to an Events object

let dataSet = {
     "entry1" : {  id: "85d55e6b-f4bf-47b0" },
     "entry2" : {  visitor_id: "6665b-7555bf-978b0" } 
}

 let flattenedMap = {};
    Object.entries(dataSet).forEach(
           ([key,value]) => Object.assign(flattenedMap, value)
     );
  

console.log("The flattened Map")
console.log(flattenedMap)

let events = [];
Object.entries(flattenedMap).forEach(
    ([key, value]) => events.push({"event_id" : value})
);

console.log("The events");
console.log(events);

Upvotes: -1

Related Questions