Skip to content

Instantly share code, notes, and snippets.

@flaf
Last active January 10, 2019 15:58
Show Gist options
  • Save flaf/fb7ef09258a56ed337ebe916a639389c to your computer and use it in GitHub Desktop.
Save flaf/fb7ef09258a56ed337ebe916a639389c to your computer and use it in GitHub Desktop.
Help me to find the pythonic way to do that...

J'ai une liste de dictionnaires l1 et chaque élément possède la clé tags dont la valeur est une liste de strings. Je cherche à filtrer ma liste via une fonction pour ne garder que les éléments qui possèdent tels ou tels tags.

Voici mon code naïf mais qui marche :

#!/usr/bin/python

def my_filter(array, tags):
    result = []
    for d in array:
        must_be_kept = True
        for tag in tags:
            if tag not in d["tags"]:
               must_be_kept = False
               break
        if must_be_kept:
            result.append(d)
    return result

l1 = [
    { "key": "foo", "tags": ["a", "b"] },
    { "key": "bar", "tags": ["b", "c"] },
    { "key": "bam", "tags": ["c", "d"] },
]

print("===> All my list:")
print(l1)

print("===> element(s) with tag c:")
print(my_filter(l1, ["c"]))

print("===> element(s) with tags a and b:")
print(my_filter(l1, ["a", "b"]))

Et ça donne bien :

~$ /tmp/test.py 
===> All my list:
[{'key': 'foo', 'tags': ['a', 'b']}, {'key': 'bar', 'tags': ['b', 'c']}, {'key': 'bam', 'tags': ['c', 'd']}]
===> element(s) with tag c:
[{'key': 'bar', 'tags': ['b', 'c']}, {'key': 'bam', 'tags': ['c', 'd']}]
===> element(s) with tags a and b:
[{'key': 'foo', 'tags': ['a', 'b']}]

Ma question : je suis sûr qu'on peut faire le même code de manière plus concise et surtout de manière plus « pythonnique ». Pouvez-vous me dire comment ? Attention, détail qui a peut-être son importance, je dois rester en Python 2.7

@flaf
Copy link
Author

flaf commented Jan 10, 2019

Solution trouvée grâce à l'excellent channel IRC #python-fr. ;)

#!/usr/bin/python

def filter_all(array, tags):
    must_be_kept = lambda d: all(tag in d["tags"] for tag in tags)
    return filter(must_be_kept, array)

def filter_any(array, tags):
    must_be_kept = lambda d: any(tag in d["tags"] for tag in tags)
    return filter(must_be_kept, array)

l1 = [
    { "key": "foo", "tags": ["a", "b"] },
    { "key": "bar", "tags": ["b", "c"] },
    { "key": "bam", "tags": ["c", "d"] },
]

print("===> All my list:")
print(l1)

print("===> element(s) with tag c:")
print(filter_all(l1, ["c"]))

print("===> element(s) with tags a *and* b:")
print(filter_all(l1, ["a", "b"]))

print("===> element(s) with tags a *or* b:")
print(filter_any(l1, ["a", "b"]))

Ce qui donne :

~$ /tmp/test.py
===> All my list:
[{'key': 'foo', 'tags': ['a', 'b']}, {'key': 'bar', 'tags': ['b', 'c']}, {'key': 'bam', 'tags': ['c', 'd']}]
===> element(s) with tag c:
[{'key': 'bar', 'tags': ['b', 'c']}, {'key': 'bam', 'tags': ['c', 'd']}]
===> element(s) with tags a *and* b:
[{'key': 'foo', 'tags': ['a', 'b']}]
===> element(s) with tags a *or* b:
[{'key': 'foo', 'tags': ['a', 'b']}, {'key': 'bar', 'tags': ['b', 'c']}]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment