Альтернативные способы цепочки итераторов в понимании списка?

#python #list #iterator #list-comprehension

#python #Список #итератор #понимание списка

Вопрос:

Я хочу объединить два или более разных итератора в понимании списка.

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

 lst1 = [chr(i) for i in range(97,123)]
lst2 = [chr(i) for i in range(65,91)]
lst = lst1 lst2
  

Однако я подумал, что должны быть какие-то другие способы сделать это красиво в одной строке, а затем я использовал это с модулем itertools,

 lst = [chr(i) for i in itertools.chain(range(97,123), range(65,91))]
  

В конце я также подумал о распаковке кортежей,

 lst = [chr(i) for i in (*range(97,123), *range(65,91))]
  

Itertools был медленнее по сравнению с двумя другими методами (распаковка кортежей была самой быстрой)

Например, символы в первом и втором диапазонах составляют список

 >>> lst1
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

>>> lst2
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
  

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

 >>> lst
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
  

Есть ли какой-либо способ улучшить это или изменить дизайн?

Комментарии:

1. Вы пробовали itertools.chain оба генератора вместо диапазонов? list(itertools.chain((chr(i) for i in range(97, 123)), (chr(i) for i in range(65, 91))))

2. Не могли бы вы предоставить пример вывода, чтобы мы могли точно видеть, какое решение вы ищете?

Ответ №1:

Вы нашли правильное решение (решения).

Примечание: itertools.chain может быть тривиально медленнее, но его преимущество в том, что он (фактически) не требует затрат памяти, и я бы рекомендовал его в целом. range уже (фактически) нулевая нагрузка на память, поэтому использование его с chain означает отсутствие каких-либо значимых затрат памяти вообще, в то время как использование распаковки в a tuple предполагает реализацию обоих range s как a tuple без реальной причины. Если размеры никогда не увеличиваются, то что угодно, но если входные данные могут быть переменной длины, chain безопаснее, чем реализация неограниченной итерации в памяти.

Конечно, для вашего конкретного случая очевидным решением (которое значительно более читабельно) является:

  import string

 lst = list(string.ascii_letters)
  

Комментарии:

1. 1 для альтернативного способа, который обеспечивает тот же порядок букв (заглавные буквы сохраняются, несмотря на меньшее числовое значение). Я полностью ожидал list(string.ascii_letters) , что меня будут заказывать противоположным образом.

2. @Adirio: На самом деле я тоже; первоначально я написал это как конкатенацию string.ascii_lowercase и string.ascii_uppercase , затем понял, что ascii_letters это уже в правильном порядке. 🙂

Ответ №2:

Это, вероятно, не так аккуратно, как список, извлеченный из пакета string , НО он решает ваш вопрос, создавая единую итерацию путем объединения двух наборов, и также должен быть достаточно эффективным.

 >>> [chr(i) for i in set(range(97,123)).union(range(65,91))]
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
  

Комментарии:

1. Три замечания: 1. Полагаться на set s для сохранения порядка — ужасная идея (и, как это бывает, это приводит к неправильному порядку, вводя сначала прописные буквы, хотя несколько удивительно, что все буквы в остальном в порядке). 2. Вам не нужно преобразовывать аргумент в union в a set ; он принимает произвольные итерации (если бы вы использовали | для объединения, вам нужно, чтобы оба были set s , но именованные методы не являются конкретными). 3. Здесь нет никакой существенной выгоды от использования set s по сравнению с простым объединением range s; распаковка двух range s в a tuple быстрее для получения одной коллекции.

2. Привет, спасибо за просвещение! Многому научился: D