Skip to content

Commit

Permalink
New dict.map() method
Browse files Browse the repository at this point in the history
Dict now have a `map()` method that return a list of values from a given
list of keys.
  • Loading branch information
bruchar1 committed May 9, 2024
1 parent f8aefe2 commit f2086f7
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
27 changes: 27 additions & 0 deletions docs/markdown/snippets/dict_map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## New `map()` method on dict

Dict now have a `map()` method that return a list of values from a given
list of keys.

It allows to keep objects in a dict, and to select needed objects from a list
of keys. For example:

```
dependencies = {
'a': dependency('a'),
'b': dependency('b'),
'c': dependency('c'),
...
}
lib_dependencies = {
'libA': ['a', 'b'],
'libB': ['b', 'c'],
...
}
libA = library('A', dependencies: dependencies.map(lib_dependencies['libA']))
libB = library('B', dependencies: dependencies.map(lib_dependencies['libB']))
...
```
17 changes: 17 additions & 0 deletions docs/yaml/elementary/dict.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,20 @@ methods:
- name: keys
returns: list[str]
description: Returns an array of keys in the dictionary.

- name: map
since: 1.5.0
returns: list
description: Returns a list of dict values for the given list of keys

posargs:
keys:
type: list[str]
description: dict keys to select

kwargs:
ignore_unknown:
type: bool
description: |
If `true`, unknown keys are skipped.
If `false`, an unknown key results in an error.
15 changes: 15 additions & 0 deletions mesonbuild/interpreter/primitives/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
from ...interpreterbase import (
ObjectHolder,
IterableObject,
KwargInfo,
MesonOperator,
typed_operator,
noKwargs,
noPosargs,
noArgsFlattening,
typed_kwargs,
typed_pos_args,
FeatureNew,

TYPE_var,

Expand All @@ -31,6 +34,7 @@ def __init__(self, obj: T.Dict[str, TYPE_var], interpreter: 'Interpreter') -> No
'has_key': self.has_key_method,
'keys': self.keys_method,
'get': self.get_method,
'map': self.map_method,
})

self.trivial_operators.update({
Expand Down Expand Up @@ -81,6 +85,17 @@ def get_method(self, args: T.Tuple[str, T.Optional[TYPE_var]], kwargs: TYPE_kwar
return args[1]
raise InvalidArguments(f'Key {args[0]!r} is not in the dictionary.')

@FeatureNew('dict.map', '1.5.0')
@noArgsFlattening
@typed_pos_args('dict.map', list)
@typed_kwargs('dict.map', KwargInfo('ignore_unknown', bool, default = False))
def map_method(self, args: T.Tuple[T.List[str]], kwargs: T.Dict[str, bool]) -> list:
keys = [k for k in args[0] if k in self.held_object] if kwargs['ignore_unknown'] else args[0]
try:
return [self.held_object[k] for k in keys]
except KeyError as e:
raise InvalidArguments(f'Key {e} is not in the dictionary.') from e

@typed_operator(MesonOperator.INDEX, str)
def op_index(self, other: str) -> TYPE_var:
if other not in self.held_object:
Expand Down
10 changes: 10 additions & 0 deletions test cases/common/188 dict/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,13 @@ d = {
assert(d['sanity'] == 1)
assert(not is_disabler(d['meson']))
assert(not is_disabler(d['host']))


# Map method
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
assert(d.map(['a', 'c', 'e']) == [1, 3, 5], 'Incorrect result for dictionary map function')
assert(d.map(['a', 'g', 'c', 'e'], ignore_unknown: true) == [1, 3, 5], 'Incorrect result for dictionary map function (ignore unknown keys)')

testcase expect_error('Key \'g\' is not in the dictionary.')
d.map(['a', 'g', 'c'])
endtestcase

0 comments on commit f2086f7

Please sign in to comment.