Канонический способ объединить списки - PullRequest
0 голосов
/ 25 июня 2018

У меня есть куча списочных представлений, которые я хотел бы объединить.

У меня есть список объектов, и я хочу создать набор списков, каждый из которых содержит некоторое свойство каждого из объектов в исходном списке. Например:

my_list = ["Kathryn", "John", "Eve", "Jack"]
initials = [x[0] for x in my_list]
upper_case = [x.upper() for x in my_list]
lower_case = [x.lower() for x in my_list]

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

Вместо этого я попытался сжать результаты получения всех свойств за одну итерацию:

initials, upper_case, lower_case = zip(*((x[0], x.upper(), x.lower()) for x in my_list))

Это работает, за исключением того, что (1) я думаю, что этот код довольно неясен, и (2) результирующие переменные на самом деле являются кортежами, а не списками, поэтому для получения списков (которые мне нужны) мне нужно сделать что-то вроде

initials, upper_case, lower_case = (list(x) for x in (initials, upper_case, lower_case))

что, уже сейчас, но особенно если я извлекаю более трех свойств, мне тоже не очень нравится внешний вид. («... из которых мне тоже не очень нравится внешность»?)

Есть ли более удовлетворительный, "чище" способ сделать это?

Ответы [ 4 ]

0 голосов
/ 27 июня 2018

Что вам нужно, это сопоставить функции со списком, чтобы получить другой список с такой же формой.Вы можете указать функции как лямбды (анонимные функции) или использовать methodcaller / itemgetter в качестве решения jpp

my_list = ["Kathryn", "John", "Eve", "Jack"]

initials =  list(map(lambda x:x[0] ,my_list))
upper_case = list(map(lambda x:x.upper() ,my_list))
lower_case = list(map(lambda x:x.lower() ,my_list))
0 голосов
/ 25 июня 2018

Проблемы, которые вы рассматриваете: ясность, вывод кортежа и списка, возможность расширения до большего числа функций.

Возможно, вы захотите рассмотреть функциональное решение, которое может добавить ясности и расширяемости.Такое решение не может быть быстрее, чем другие решения.Вот пример:

from operator import itemgetter, methodcaller

my_list = ['Kathryn', 'John', 'Eve', 'Jack']

funcs = (itemgetter(0), methodcaller('upper'), methodcaller('lower'))

i, u, l = map(list, (map(func, my_list) for func in funcs))

print(i, u, l, sep='\n')

['K', 'J', 'E', 'J']
['KATHRYN', 'JOHN', 'EVE', 'JACK']
['kathryn', 'john', 'eve', 'jack']
0 голосов
/ 25 июня 2018

Другой СУХОЙ способ сделать это:

def comprehend(func, iterable):
    return [func(item) for item in iterable]

my_list = ["Kathryn", "John", "Eve", "Jack"]

Initials = comprehend(lambda x:x[0], my_list)
Upper_case = comprehend(lambda x:x.upper(), my_list)
Lower_case = comprehend(lambda x:x.lower(), my_list)
0 голосов
/ 25 июня 2018

Проще говоря, используйте петлю for вместо:

my_list = ["Kathryn", "John", "Eve", "Jack"]
initials = []
upper_case = []
lower_case = []
for x in my_list:
    initials.append(x[0])
    upper_case.append(x.upper())
    lower_case.append(x.lower())

Как общее правило: первая и главная цель понимания списка состоит не в том, чтобы быть быстрее, а в том, чтобы сделать его более читаемым (за счет уменьшения «строкового шума»). Если использование понимания списка делает ваш код менее читаемым, не используйте понимание списка.

Примечание: это предполагает, что вы, конечно, хотите оптимизировать для удобства чтения - иногда вы действительно хотите оптимизировать для скорости, даже если это делает код менее читабельным, и это тоже нормально (если вы компенсируете четкими комментариями / документацией, чтобы вы не хочу привязывать себя к ближайшему дереву, когда вам придется поддерживать этот код несколько месяцев спустя).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...