Могу ли я сократить понимание списка на два списка, основываясь на двух значениях? - PullRequest
3 голосов
/ 27 декабря 2010

У меня есть следующий код.

sum_review = reduce(add,[book['rw'] for book in books])
sum_rating = reduce(add,[book['rg'] for book in books])
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items

То, что я хотел бы, это.

sum_review,sum_rating = reduce(add,([book['rw'],[book['rg']) for book in books])
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items

Очевидно, это не работает. Как я могу решить эту избыточность, без регулярного цикла?

Ответы [ 5 ]

9 голосов
/ 27 декабря 2010

Я бы не использовал здесь уменьшение.Для чего-то такого простого используйте sum:

sum_review = sum(book['rw'] for book in books)
sum_rating = sum(book['rg'] for book in books)

На мой взгляд, эта более простая версия не требует рефакторинга для удаления избыточности.С двумя пунктами (rw и rg) я думаю, что лучше просто оставить все как есть.

3 голосов
/ 27 декабря 2010

Существует два типичных подхода к упрощению кода:

  1. Сверху вниз: сначала получите значения, а затем транспонируйте их с помощью zip(*iterable). Это также круто, потому что он повторяет коллекцию только один раз:

    values = ((book["rw"], book["rg"]) for book in books)
    avg_review, avg_rating = [sum(xs) / len(books) for xs in zip(*values)]
    
  2. Вверх: создайте функцию для абстрагирования операции:

    get_avg = lambda xs, attr: sum(x[attr] for x in xs) / len(xs)
    avg_review = get_avg(books, "rw")
    avg_rating = get_avg(books, "rg")
    
2 голосов
/ 27 декабря 2010

Вы должны предпочесть ясность, а не оптимизацию.За 3 года использования Python мне пришлось только дважды профилировать, чтобы обнаружить узкие места в производительности.Ваш оригинальный код понятен и эффективен.Сжатие первых двух строк в одну ухудшает читабельность и практически не влияет на производительность.

Если бы у меня было для пересмотра вашего кода, это будет выглядеть так:пять строк кода до двух с улучшением ясности.)

1 голос
/ 27 декабря 2010

Как я могу решить эту избыточность

Создав функцию, конечно:

def average_value(items, key):
  values = [x[key] for x in items]
  return sum(items) / len(items)

avg_review, avg_rating = average_value(books, 'rw'), average_value(books, 'rg')
1 голос
/ 27 декабря 2010
sum_review, sum_rating = reduce(lambda a,b: (a[0] + b[0], a[1]+b[1]), ((book['rw'], book['rg']) for book in books), (0,0) )
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items

(проверено)

...