séparer élégamment une liste (ou un dict) en deux via une fonction arbitraire en python
y a-t-il un moyen élégant de diviser une liste/dict en deux listes/dicts en python, en utilisant une fonction de splitter arbitraire?
je pourrais facilement avoir deux listes compréhensibles, ou deux sélections, mais il me semble qu'il devrait y avoir une meilleure façon de le faire qui évite de répéter chaque élément deux fois.
je pourrais le faire facilement avec une boucle for et if, mais qui prend quelque chose comme 7 lignes de code pour ce qui devrait être très simple opération.
des idées?
Edit:
juste pour référence, mes deux solutions seraient,
# given dict cows, mapping cow names to weight
# fast solution
fatcows = {}
thincows = {}
for name, weight in cows:
if weight < 100:
thincows[name] = weight
else:
fatcows[name] = weight
# double-list-comprehension solution would be
fatcows = {name: weight for name, weight in cows.items() if weight > 100}
thincows = {name: weight for name, weight in cows.items() if weight < 100}
je pensais qu'il devait y avoir quelque chose de plus élégant que cela que je n'ai jamais pensé, quelque chose comme:
thincows, fatcows = ??? short expression involving cows ???
je sais que c'est possible de le faire en écrivant des fonctions d'ordre supérieur des choses à faire pour moi, et je sais comment le faire manuellement. Je me demandais juste s'il y avait quelque chose de très élégant dans le langage pour le faire pour moi.
c'est comme si vous pouvez écrire vos propres sous-Programmes et autres pour faire un SELECT sur une liste, ou vous pouvez juste dire
thincows = select(cows, lambda c: c.weight < 100)
j'espérais qu'il y aurait certains de la même manière élégante de fractionnement la liste, avec un pass
6 réponses
Plus de plaisir avec les vaches :)
import random; random.seed(42)
cows = {n:random.randrange(50,150) for n in 'abcdefghijkl'}
thin = {}
for name, weight in cows.iteritems():
thin.setdefault(weight < 100, {})[name] = weight
>>> thin[True]
{'c': 77, 'b': 52, 'd': 72, 'i': 92, 'h': 58, 'k': 71, 'j': 52}
>>> thin[False]
{'a': 113, 'e': 123, 'l': 100, 'g': 139, 'f': 117}
pourquoi pas 3 lignes?
fatcows, thincows = {}, {}
for name, weight in cows.items():
(fatcows if weight > 50 else thincows)[name] = weight
testé:
>>> cows = {'bessie':53, 'maud':22, 'annabel': 77, 'myrna':43 }
>>> fatcows, thincows = {}, {}
>>> for name, weight in cows.items():
... (fatcows if weight > 50 else thincows)[name] = weight
...
>>> fatcows
{'annabel': 77, 'bessie': 53}
>>> thincows
{'maud': 22, 'myrna': 43}
N'importe quelle solution va prendre du temps pour calculer, que ce soit par deux passes à travers la liste ou une passe qui fait plus de travail par item. La manière la plus simple est simplement d'utiliser les outils qui sont à votre disposition:itertools.ifilter
et itertools.ifilterfalse
:
def bifurcate(predicate, iterable):
"""Returns a tuple of two lists, the first of which contains all of the
elements x of `iterable' for which predicate(x) is True, and the second
of which contains all of the elements x of `iterable` for which
predicate(x) is False."""
return (itertools.ifilter(predicate, iterable),
itertools.ifilterfalse(predicate, iterable))
Il peut être fait avec un genex, de tri et d'
solution Brute-force:
def bifurcate(pred, seq):
if pred is None:
pred = lambda x: x
res1 = []
res2 = []
for i in seq:
if pred(i):
res1.append(i)
else:
res2.append(i)
return (res2, res1)
solution élégante:
import itertools
import operator
def bifurcate(pred, seq):
if pred is None:
pred = lambda x: x
return tuple([z[1] for z in y[1]] for y in
itertools.groupby(sorted((bool(pred(x)), x) for x in seq),
operator.itemgetter(0)))
assez simple, sans aucun outil extérieur:
my_list = [1,2,3,4]
list_a = []
list_b = []
def my_function(num):
return num % 2
generator = (list_a.append(item) if my_function(item) else list_b.append(item)\
for item in my_list)
for _ in generator:
pass
OK, c'est à propos des vaches :)
cows = {'a': 123, 'b': 90, 'c': 123, 'd': 70}
select = lambda cows, accept: {name: weight for name, weight
in cows.items()
if accept(weight)}
thin = select(cows, lambda x: x < 100)
fat = select(cows, lambda x: x > 100)