Среднее число номеров, хранящихся в виде строк в списке Python

Я хочу рассчитать среднее значение нескольких списков в python. Эти списки содержат числа как строки. Пустая строка не равна нулю, это означает отсутствие значения.

Лучшее, что я мог придумать, это. Есть ли более элегантный, сжатый и эффективный способ написать это?

num = ['1', '2', '', '6'] total = sum([int(n) if n else 0 for n in num]) length = sum([1 if n else 0 for n in num]) ave = float(total)/length if length > 0 else '-' 

PS Я использую Python 2.7.x, но рецепты для Python 3.x приветствуются

5 Solutions collect form web for “Среднее число номеров, хранящихся в виде строк в списке Python”

 num = ['1', '2', '', '6'] L = [int(n) for n in num if n] ave = sum(L)/float(len(L)) if L else '-' 

или

 num = ['1', '2', '', '6'] L = [float(n) for n in num if n] avg = sum(L)/len(L) if L else '-' 

В Python 3.4 используйте библиотеку статистики :

 from statistics import mean num = ['1', '2', '', '6'] ave = mean(int(n) if n else 0 for n in num) 

Вы можете отменить квадратные скобки. sum принимает выражения генератора:

 total = sum(int(n) if n else 0 for n in num) length = sum(1 if n else 0 for n in num) 

А так как генераторы дают значение только тогда, когда это необходимо, вы сохраняете дорогостоящую стоимость хранения списка в памяти. Особенно, если вы имеете дело с большими данными.

Вот несколько вариантов решения OP по сравнению с решением aIKid по сравнению с решениями gnibbler, используя список из 100 000 номеров в 1..9 (плюс пустая строка) и 10 проб:

 import timeit setup = ''' from __main__ import f1, f2, f3, f4 import random random.seed(0) choices = ['1', '2', '3', '4', '5', '6', '7', '8', '9', ''] num = [random.choice(choices) for _ in range(10**5)] ''' def f1(num): # OP total = sum([int(n) if n else 0 for n in num]) length = sum([1 if n else 0 for n in num]) ave = float(total)/length if length > 0 else '-' return ave def f2(num): # aIKid total = sum(int(n) if n else 0 for n in num) length = sum(1 if n else 0 for n in num) ave = float(total)/length if length > 0 else '-' return ave def f3(num): # gnibbler 1 L = [int(n) for n in num if n] ave = sum(L)/float(len(L)) if L else '-' return ave def f4(num): # gnibbler 2 L = [float(n) for n in num if n] ave = sum(L)/float(len(L)) if L else '-' return ave number = 10 things = ['f1(num)', 'f2(num)', 'f3(num)', 'f4(num)'] for thing in things: print(thing, timeit.timeit(thing, setup=setup, number=number)) 

Результат:

 f1(num) 1.8177659461490339 # OP f2(num) 2.0769015213241513 # aIKid f3(num) 1.6350571199344595 # gnibbler 1 f4(num) 0.807052779158564 # gnibbler 2 

Похоже, решение gnibbler, использующее float является самым быстрым здесь.

Немного другой подход

 num = ['1', '2', '', '6'] total = reduce(lambda acc, x: float(acc) + (float(x) if x else 0),num,0) length = reduce(lambda acc, x: float(acc) + (1 if x else 0),num,0) average = (',',total/length)[length > 0] 
  • Что означают обратные линии для интерпретатора python: `num`
  • Префикс prepend для перечисления элементов со списком
  • Сделать Javascript выполнимым списком
  • Замена элемента списка содержимым другого списка
  • Как эффективно фильтровать вычисленные значения в понимании списка Python?
  • Pythonic Style для понимания многострочного списка
  • Странное поведение лямбды в понимании списка
  • Альтернатива пониманию списка, если будет только один результат
  • Python - лучший язык программирования в мире.