diff --git a/README.md b/README.md index 134a19a..58735bc 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ lng = loc.get_decimal('longitude') - [`clone`](#clone) - [`dump`](#dump) - [`filter`](#filter) + - [`find`](#find) - [`flatten`](#flatten) - [`groupby`](#groupby) - [`invert`](#invert) @@ -265,6 +266,15 @@ predicate = lambda k, v: v is not None f = d.filter(predicate) ``` +- #### find + +```python +# Return the first match searching for the given keys/keypaths. +# If no result found, default value is returned. +keys = ['a.b.c', 'm.n.o', 'x.y.z'] +f = d.find(keys, default=0) +``` + - #### flatten ```python diff --git a/benedict/core/__init__.py b/benedict/core/__init__.py index 74128d6..5a0608c 100644 --- a/benedict/core/__init__.py +++ b/benedict/core/__init__.py @@ -4,6 +4,7 @@ from benedict.core.clean import clean from benedict.core.clone import clone from benedict.core.dump import dump from benedict.core.filter import filter +from benedict.core.find import find from benedict.core.flatten import flatten from benedict.core.groupby import groupby from benedict.core.invert import invert diff --git a/benedict/core/find.py b/benedict/core/find.py new file mode 100644 index 0000000..a75f26c --- /dev/null +++ b/benedict/core/find.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + + +def find(d, keys, default=None): + for key in keys: + if key in d: + return d.get(key, default) + return default diff --git a/benedict/dicts/__init__.py b/benedict/dicts/__init__.py index 6fef229..d50a904 100644 --- a/benedict/dicts/__init__.py +++ b/benedict/dicts/__init__.py @@ -4,6 +4,7 @@ from benedict.core import clean as _clean from benedict.core import clone as _clone from benedict.core import dump as _dump from benedict.core import filter as _filter +from benedict.core import find as _find from benedict.core import flatten as _flatten from benedict.core import groupby as _groupby from benedict.core import invert as _invert @@ -86,6 +87,13 @@ class benedict(KeypathDict, IODict, ParseDict): """ return _filter(self, predicate) + def find(self, keys, default=None): + """ + Return the first match searching for the given keys. + If no result found, default value is returned. + """ + return _find(self, keys, default) + def flatten(self, separator='_'): """ Return a new flattened dict using the given separator diff --git a/tests/core/test_find.py b/tests/core/test_find.py new file mode 100644 index 0000000..2b81a46 --- /dev/null +++ b/tests/core/test_find.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +from benedict.core import find as _find + +import unittest + + +class find_test_case(unittest.TestCase): + + def test_find_with_single_result(self): + i = { + 'a': 1, + 'b': 2, + 'c': 3, + 'd': None, + } + o = _find(i, ['x', 'y', 'b', 'z'], 5) + self.assertEqual(o, 2) + + def test_find_with_multiple_results(self): + i = { + 'a': 1, + 'b': 2, + 'c': 3, + 'd': None, + } + o = _find(i, ['a', 'x', 'b', 'y']) + self.assertEqual(o, 1) + + def test_find_with_no_result(self): + i = { + 'a': 1, + 'b': 2, + 'c': 3, + 'd': None, + } + o = _find(i, ['x', 'y', 'z']) + self.assertEqual(o, None) + + def test_find_with_no_result_and_default(self): + i = { + 'a': 1, + 'b': 2, + 'c': 3, + 'd': None, + } + o = _find(i, ['x', 'y', 'z'], 5) + self.assertEqual(o, 5) diff --git a/tests/dicts/test_benedict.py b/tests/dicts/test_benedict.py index d87ab9f..2afbaed 100644 --- a/tests/dicts/test_benedict.py +++ b/tests/dicts/test_benedict.py @@ -368,6 +368,21 @@ class benedict_test_case(unittest.TestCase): self.assertEqual(f, r) self.assertTrue(isinstance(f, benedict)) + def test_filter(self): + d = { + 'a': 1, + 'b': 2, + 'c': { + 'd': { + 'e': 3, + 'f': 4, + } + }, + } + b = benedict(d) + r = b.find(['x.y.z', 'a.b.c', 'c.d.e']) + self.assertEqual(r, 3) + def test_flatten(self): d = { 'a': 1,