Reputation: 2253
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
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
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
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
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
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
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