2010-01-21 5 views
1

J'essaie de trouver une belle façon de résumer une liste et une liste de listes dans la même fonction, jusqu'à présent, j'ai:Pythonic manière des listes et des listes de sommer les listes

import operator 
""" 
Fails late for item = ['a', 'b'] 
""" 
def validate(item): 
    try: 
     return sum(item) == sum(range(1, 10)) 
    except TypeError: 
     return sum(reduce(operator.add, item)) == sum(range(1, 10)) 

""" 
Not valid for item = [1,2,[3,4,5]] 
""" 
def validate2(item): 
     if isinstance(item[0], int): 
      return sum(item) == sum(range(1, 10)) 
     else: 
      return sum(reduce(operator.add, item)) == sum(range(1, 10)) 


print validate([1, 2, 3, 4, 5, 6, 7, 8, 9]) 
print validate([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 

print validate2([1, 2, 3, 4, 5, 6, 7, 8, 9]) 
print validate2([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 

. ..mais aucun de ceux-ci me semble tout à fait raison (raisons dans les cordes doc). Ce que je veux savoir, c'est s'il y a une meilleure façon de faire la somme des listes et des listes de listes qui ne nécessite pas d'attraper des exceptions ou d'analyser réellement la liste avant que la fonction ne décide quoi faire.

Évidemment, je m'attends toujours à ce que ['a', 'b'] soit invalide.

Répondre

3

Ne pas oublier de décrire exactement ce que vous essayez de faire. Je suppose que vous voulez dire que toutes les valeurs doivent être additionnées à une seule valeur, et ne pas être par exemple. [[1,2], [3,4]] -> [3,7]. Voici une récursion simple; cinq lignes de code si vous passez des tests:

def sums(it): 
    """ 
    >>> sums(1) 
    1 
    >>> sums([1,2,3]) 
    6 
    >>> sums([1,2,3,[4,5]]) 
    15 
    >>> sums(['a','b']) 
    Traceback (most recent call last): 
    ... 
    TypeError: unsupported operand type(s) for +: 'int' and 'str' 
    """ 
    if getattr(it, "__iter__", None): 
     return sum(map(sums, it)) 
    else: 
     return it 

if __name__ == "__main__": 
    import doctest 
    doctest.testmod() 
+0

Je n'avais pas vu le module doctest avant, merci de me l'avoir présenté +1 – MattyW

5

Peut-être trouvez-vous plus facile d'aplatir la liste en premier?

def flatten(xs): 
    for x in xs: 
     try: 
      sub = iter(x) 
     except TypeError: 
      yield x 
     else: 
      for y in flatten(sub): 
       yield y 

Avec ce qui précède, vous pouvez le faire:

In [4]: fs = flatten([1,2,[3,4,[5,6],7],8,[9,10]]) 

In [5]: list(fs) 
Out[5]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
+0

Vous pouvez déplacer 'pour x dans xs' à l'intérieur de' else: '(et changer pour' yield xs' dans l'exception) pour que cela fonctionne même sur les scalaires. J'aime toujours mettre des conditions de récurrence à l'entrée de la fonction. –

+0

@Beni: C'est vrai, c'est possible quand on le souhaite. Le bit après le 'else:' deviendrait 'pour x dans xs: pour y dans aplatir (x): céder y'. Merci pour le commentaire! –

0

Le module externe numpy a de nombreuses opérations (y compris sum()) qui fonctionnent de façon similaire sur scalaires, des vecteurs, des matrices et des tableaux même dimensions plus ...

Notez cependant que cela ne fonctionne pas sur des listes mixtes comme [1,2,[3,4,5]], uniquement des matrices carrées! Cela ne répond donc pas exactement à votre question.

Questions connexes