Создайте список кортежей со смежными элементами списка, если условие истинно
Я пытаюсь создать список кортежей, где содержимое кортежа - это число 9
и число перед ним в списке.
Список ввода:
myList = [1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
Желаемый результат:
sets = [(8, 9), (4, 9), (7, 9)]
Код:
sets = [list(zip(myList[i:i], myList[-1:])) for i in myList if i==9]
Текущий результат:
[[], [], []]
Ответы
Ответ 1
Более чистый питоновский подход:
>>> [(x,y) for x,y in zip(myList, myList[1:]) if y == 9]
[(8, 9), (4, 9), (7, 9)]
Что делает вышеприведенный код:
-
zip(some_list, some_list[1:])
создаст список пар смежных элементов.
- Теперь с этим кортежем, фильтруйте при условии, что второй элемент равен
9
. Вы закончили:)
Ответ 2
Часть вашей проблемы заключается в том, что myList[i:i]
всегда будет возвращать пустой список. Конец среза является исключительным, поэтому, когда вы выполняете a_list[0:0]
, вы пытаетесь взять элементы a_list
, которые существуют между индексом 0 и индексом 0.
Вы на правильном пути, но вы хотите закрепить этот список.
[(x, y) for x, y in zip(myList, myList[1:]) if y==9]
Ответ 3
Вы были довольно близки, я покажу вам альтернативный способ, который может быть более интуитивным, если вы только начинаете:
sets = [(myList[i-1], myList[i]) for i in range(len(myList)) if myList[i] == 9]
Получить индекс в диапазоне длины списка, а если значение в позиции i
равно 9
, возьмите соседние элементы.
Результат:
sets
[(8, 9), (4, 9), (7, 9)]
Это менее эффективно, чем другие подходы, но я решил удалить его, чтобы показать вам другой способ сделать это. Вы можете сделать это быстрее, используя enumerate()
вместо этого:
sets = [(myList[i-1], j) for i, j in enumerate(myList) if j == 9]
Обратите внимание, что в случае края, где myList[0] = 9
поведение понимания без zip
, а поведение понимания с помощью zip
отличается.
В частности, если myList = [9, 1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
, то:
[(myList[i-1], myList[i]) for i in range(len(myList)) if myList[i] == 9]
# results in: [(8, 9), (8, 9), (4, 9), (7, 9)]
а
[(x, y) for x, y in zip(myList, myList[1:]) if y==9]
# results in: [(8, 9), (4, 9), (7, 9)]
Вам решать, какой из них соответствует вашим критериям, я просто указываю, что они не ведут себя одинаково во всех случаях.
Ответ 4
Вы также можете сделать это без нарезки, создав итераторы:
l = myList = [1,8,9,2,4,9,6,7,9,8]
it1, it2 = iter(l), iter(l)
# consume first element from it2 -> leaving 8,9,2,4,9,6,7,9,8
next(it2, "")
# then pair up, (1,8), (8,9) ...
print([(i, j) for i,j in zip(it1, it2) if j == 9])
Или используйте парный рецепт, чтобы создать свои пары
from itertools import tee, izip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
Если вы используете python3, просто импортируйте tee и используйте обычный zip.
Ответ 5
Неудивительно, что никто не добавил функциональный подход.
Другой альтернативный ответ - filter
. Эта встроенная функция возвращает итератор (список в Python2), состоящий из всех элементов, присутствующих в списке, которые возвращают True
для определенной функции
>>> myList = [1,8,9,2,4,9,6,7,9,8]
>>> list(filter(lambda x:x[1]==9,zip(myList, myList[1:])))
[(8, 9), (4, 9), (7, 9)]
Следует отметить, что вызов list
требуется только в python3 +. Разница между функциональным подходом и пониманием списков обсуждается в в этом сообщении.
Ответ 6
Мое решение похоже на одно из продвинутых Jim с проверкой нулевого индекса
myList = [9, 1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
[(myList[i-1], x) for i, x in enumerate(myList) if x==9 and i!=0]
# [(8, 9), (4, 9), (7, 9)]