Reputation:
I am trying to create a list of tuples where the tuple contents are the number 9
and the number before it in the list.
Input List:
myList = [1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
Desired Output:
sets = [(8, 9), (4, 9), (7, 9)]
Code:
sets = [list(zip(myList[i:i], myList[-1:])) for i in myList if i==9]
Current Result:
[[], [], []]
Upvotes: 31
Views: 6112
Reputation: 2743
My solution is similar to one of Jim's advanced with zero-index check
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)]
Upvotes: 1
Reputation: 52071
It is really surprising that no one has added a functional approach.
Another alternative answer is using a filter
. This builtin function returns an iterator (list in Python2) consisting of all the elements present in the list that return True
for a particular function
>>> 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)]
It is to be noted that the list
call is needed only in python3+. The difference between the functional approach and list comprehensions is discussed in detail in this post.
Upvotes: 5
Reputation: 160367
You were pretty close, I'll show you an alternative way that might be more intuitive if you're just starting out:
sets = [(myList[i-1], myList[i]) for i in range(len(myList)) if myList[i] == 9]
Get the index in the range of the list lenght, and if the value at the position i
is equal to 9
, grab the adjacent elements.
The result is:
sets
[(8, 9), (4, 9), (7, 9)]
This is less efficient than the other approaches but I decided to un-delete it to show you a different way of doing it. You can make it go a bit faster by using enumerate()
instead:
sets = [(myList[i-1], j) for i, j in enumerate(myList) if j == 9]
Take note that in the edge case where myList[0] = 9
the behavior of the comprehension without zip
and the behavior of the comprehension with zip
is different.
Specifically, if myList = [9, 1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
then:
[(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)]
while:
[(x, y) for x, y in zip(myList, myList[1:]) if y==9]
# results in: [(8, 9), (4, 9), (7, 9)]
It is up to you to decide which of these fits your criteria, I'm just pointing out that they don't behave the same in all cases.
Upvotes: 7
Reputation: 180391
You can also do it without slicing by creating iterators:
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])
Or use the pairwise recipe to create your pairs
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)
If using python3, just import tee and use the regular zip.
Upvotes: 6
Reputation: 9986
Part of your issue is that myList[i:i]
will always return an empty list. The end of a slice is exclusive, so when you do a_list[0:0]
you're trying to take the elements of a_list
that exist between index 0 and index 0.
You're on the right track, but you want to zip the list with itself.
[(x, y) for x, y in zip(myList, myList[1:]) if y==9]
Upvotes: 16
Reputation: 44444
Cleaner Pythonic approach:
>>> [(x,y) for x,y in zip(myList, myList[1:]) if y == 9]
[(8, 9), (4, 9), (7, 9)]
What is the code above doing:
zip(some_list, some_list[1:])
would generate a list of pairs of adjacent elements.9
. You're done :)Upvotes: 43