Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a list of tuples with adjacent list elements if a condition is true

People also ask

How do you split a list based on a condition in Python?

split() , to split the list into an ordered collection of consecutive sub-lists. E.g. split([1,2,3,4,5,3,6], 3) -> ([1,2],[4,5],[6]) , as opposed to dividing a list's elements by category. Discussion of the same topic on python-list. IMAGE_TYPES should be a set instead of a tuple: IMAGE_TYPES = set('.

How do you find adjacent elements in a list?

The elements are iterated over using 'enumerate' and depending on the value of the index, the output is determined. If index value is 0, the element in first index is appended to the empty list. If index is equal to length of list minus 1, the element in previous index is appended to empty list.

Can a tuple contains a list as an element?

A tuple can contain a list as an element.

Can append be used for tuples?

Python tuple is an immutable object. Hence any operation that tries to modify it (like append) is not allowed.


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.
  • Now with that tuple, filter on the condition that the second element is equal to 9. You're done :)

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]

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.


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.


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.


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)]