Is there a way to filter a map without duplicating it?

Viewed 62

I have to filter this map:

Map<int, String> example = <int,string>{
100 : 'Flutter'
200 : 'SUPERFLUTTER'
300 : 'dart'
}

The filter should only return the entries that have the filter parameter, if the filter parameter is 'dart' my filter function must return this:

Map<int, String> output = <int,string>{
300 : 'dart'
}

I'm using this function to filter:

Map<int,String> filterdMap (Map<int,String> input, String filter) {
return Map.from(input)
    ..removeWhere(
      (key, value) => !value.toLowerCase().contains(filter),
    );
}

It works, but I believe I am duplicating the map unnecessarily. Is there any other way to solve this without duplicating the map?

1 Answers

You want to create a new map, which contains only the entries of an existing map which satisfies some criterion. In this case the criterion is only about the value.

I agree that copying the entire map, just to remove some of the entries afterwards, seems unnecessarily expensive. Not in time, it's still just linear in the input, but the memory use is excessive if most entries end up being removed.

There is the very direct approach:

Map<int, String> filtered = {};
input.forEach((k, v) {
  if (v.toLowerCase().contains(filter)) {
    filtered[k] = v;
  }
});
// done.

That's a completely valid approach. Some people prefer a more flow-based and functional approach, but that isn't necessarily better or more efficient.

If I wanted to do it as a one-liner, I'd work with entries:

var filtered = Map.fromEntries(input.entries.where((e) =>
    e.value.toLowerCase().contains(filter)));

By filtering the entries, not just the values, you retain the key along with the value, so you can build a map from it.

That's also the same as:

var filtered = {for (var e in input.entries) 
    if (e.value.toLowerCase().contains(filter)) e.key: e.value};

as @jamesdlin suggests, but this is actually a case where I prefer the non-literal syntax because it doesn't require me to mention the key. (I also won't try to predict which approach is faster without running actual benchmarks.)

Related