Python Forum
Check common element in tuples
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Check common element in tuples
#1
Hello,

I would compare multiple elements with a previous tuple in a list of tuples.

Example :

Input :

Ts = [(45,50,30,21), (30,9,56,3), (56,10,21,4), (41,30,50,56)]
Desired output :

Output:
1 : false 2 : true 3 : false 4 : true
I would like to now when an element of a tuple is in the previous tuple. Here, the second have one common number with the first (30), so it is true.
The third has none number in common with the second, so it is false.
The fourth has one number in common with the third, so it is true.

In another code, I would check if a number is in the previous list with a difference of one (exemple : 3 in the second list, 4 in the third list).

Input :

Ts = [(45,50,30,21), (30,9,56,3), (56,10,17,4), (41,30,50,56)]
Desired output :

Output:
1 : false 2 : false 3 : true 4 : false
I’ve made a lot of research and some attempts, nothing concluding.
Can you help me please ?

Thank you.
Reply
#2
I think your result is wrong. It should be [False, True, True, True]. ts[2][0] == ts[1][2] == 56. I didn't notice until I ran you list with this code.
def find_matches(tuples):
    result = [True]
    for i in range(len(tuples)-1):
        pair = list(set(tuples[i])) + list(set(tuples[i+1]))  // Protect against duplicates in a list
        result.append(len(set(pair)) == len(pair))
    return result
                   
print(find_matches([(45,50,30,21), (30,9,56,3), (57,10,21,4), (41,30,50,56)]))
Converting a list to a set removes all duplicate elements. If we have two lists l1 and l2, there are no duplicates if:
len(l1+l2) == len(set(l1+l2))

To protect against a l1 or l2 containing duplicates I convert the lists to sets before combining.

If you don't like all the set and list stuff you can search for each element.
def find_matches(tuples):
    result = [False]*len(tuples)
    prev = tuples[0]
    for index, t in enumerate(tuples[1:]):
        for value in t:
            if value in prev:
                result[index+1] = True
                break
        prev = t
    return result
Reply
#3
I don’t understand the result of your first code. Can you explain it a little bit more please ?

About the result, I confirm my desired output :

Output:
1 : false 2 : true 3 : false 4 : true
Because :

False - None number of the first tuple exist in a previous tuple (because there is not previous tuple)
True - One number of the second tuple is inside the first tuple (number : 30)
False – None number of the third tuple is inside the second tuple
True – One number of the fourth tuple is inside the third tuple

But if a number of the fourth tuple is inside the second tuple, it doesn’t mean that the result will be true, because the result analyzes only the fourth with the third, the third with the second.
Reply
#4
Quote:Ts = [(45,50,30,21), (30,9,56,3), (56,10,17,4), (41,30,50,56)]
The third tuple starts with 56 which also appears in the second tuple. If that shouldn't result in setting result[2] = True then I don't understand your tuple matching rule.

You may not understand "result" in the first example because there is an error. I messed up what True and False meant:
def find_matches(tuples):
    result = [False]  # <- Was incorrectly set to True
    for i in range(len(tuples)-1):
        pair = list(set(tuples[i])) + list(set(tuples[i+1]))  // Protect against duplicates in a list
        result.append(len(set(pair)) != len(pair))  # And corresponding error here.
    return result
                    
print(find_matches([(45,50,30,21), (30,9,56,3), (57,10,21,4), (41,30,50,56)]))
What this program does is grab two consecutive tuples and add them together. First time through it creates a list from the first two tuples: (45,50,30,21) and (30,9,56,3) and calls this pair.

pair = [45,50,30,21,30,9,56,3]

Then it compares the length of pair to the lenght of set(pair). Creating a set from a list removes any duplicate values, so the only way len(pair) == len(set(pair)) is if all values in pair are unique.

pair = [45,50,30,21,30,9,56,3], set(pair) = {3,9,45,50,21,56,30}. len(pair) != len(set(pair))

I ran the code on a few different test cases and noticed it failed for tuples like this:

Ts = [(1,1,1,1), (2,2,2,2), (3,3,3,3), 4,4,4,4)]

The result for this should be [False, False, False, False] but it came up [False, True, True, True]. The reason is that set(tuple) removes all duplicates, so (1,1,1,1,2,2,2,2) becomes (1,2). To guard against this I need to remove all duplicates from each tuple before combining them in pair.
pair = list(set((1,1,1,1)) + list(set((2,2,2,2)) == [1] + [2] == [1, 2]
Reply
#5
For your second list, where the result is True if t1 and t2 contain a value that is different by 1:
def find_matches(tuples):
    result = [False]*len(tuples)
    prev = tuples[0]
    for index, t in enumerate(tuples[1:]):
        for v1 in t:
            for v2 in prev:
                if abs(v1 - v2) == 1:
                    result[index+1] = True
                    break
        prev = t
    return result

Ts = [(45,50,30,21), (30,9,56,3), (56,10,17,4), (41,30,50,56)]
print(find_matches(Ts))
Reply
#6
You have 4 tuples, so actually only 3 comparisons to the previous tuple can be made. I took a stab in the code below. I gave a pass "True" to the first tuple, then for each subsequent tuple compared each element to see if in the prior tuple. If so, print True, if not continue until have checked all the elements in the tuple at which point print False. See if this works for you.

def find_tuple_matches(tuples) :
    for count, mississippi in enumerate(tuples) :
        if count == 0:
            print('False')
            continue
        flag = False
        for tupelo in mississippi :
            if tupelo in tuples[count-1] :
                print('True')
                flag = True
                break
            
        if not flag :
            print('False')

find_tuple_matches([(45,50,30,21), (30,9,56,3), (57,10,21,4), (41,30,50,56)])
Reply
#7
Was looking at another question about sets and I would like to redo my first answer. If looking for common elements in sets why not use "&"?
def find_matches(tuples):
    result = [False]
    prev = set(tuples[0])
    for t in tuples[1:]:
        t = set(t)
        result.append(len(t & prev) != 0)
        prev = t
    return result
Reply
#8
My understanding of this task is:

- iterate pairwise over items of list
- return bool value whether pair has intersection

One way of implementing it:

from itertools import tee

def find_matches(list_):
    a, b = tee(list_)
    next(b, None)
    return [False] + [bool(set(x).intersection(y)) for (x, y) in zip(a, b)]

# usage:
list_ = [(45,50,30,21), (30,9,56,3), (56,10,21,4), (41,30,50,56)]
find_matches(list_) -> [False, True, True, True]
Pairwise iteration is adopted from itertools recipes from itertools documentation (function named pairwise). Documentation as whole as well as recipes have lot of 'goodies' to get inspiration from Smile .
DeaD_EyE likes this post
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#9
In another thread "any()" was used to cleanly combine multiple tests into a short if statement.

https://python-forum.io/Thread-IF-and-list

That's why I try to read all the posts from all the different groups because I learn something almost every day. any() works nicely for this problem too.
def find_matches(tuples):
    result = [False]
    for p, n in zip(tuples, tuples[1:]):
        result.append(any(x in p for x in n))
    return result
 
def find_off_by_1(tuples):
    result = [False]
    for p, n in zip(tuples, tuples[1:]):
        result.append(any(abs(x-y)==1 for x in n for y in p))
    return result
 
Ts = [(45,50,30,21), (30,9,56,3), (56,10,17,4), (41,30,50,56)]
print(find_matches(Ts))
print(find_off_by_1(Ts))
Output:
[False, True, True, True] [False, False, True, False]
I like how using any() results in both solutions being very similar. I also like how zip keeps showing itself to be more and more versatile each time I use it.
Reply
#10
The best way to check for common elements is to use sets.

A proper solution would be a list of 3 values - since you compare 4 neighbours, but - taking your restraints into account.

from functools import reduce
tuples = [(45,50,30,21), (30,9,56,3), (56,10,21,4), (41,30,50,56)]
reduce(lambda res, pair: res+ [bool(set(pair[0]).intersection(pair[1]))],
      zip(tuples, tuples[1:]), [False])
Spelling it out in less golf-y way

def common_in_neigbours(tuples):
    result = [False]
    for left, right in zip(tuples, tuples[1:]):
        result.append(bool(set(left).intersection(right)))
    return result
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How to solve this simple problem? Check if cvs first element is the same in each row? thesquid 2 1,179 Jun-14-2022, 08:35 PM
Last Post: thesquid
  check if element is in a list in a dictionary value ambrozote 4 1,879 May-11-2022, 06:05 PM
Last Post: deanhystad
  How to check if my argument is a tuple with 3 tuples zarox 1 1,795 Nov-15-2020, 06:50 PM
Last Post: DougBTX
  Unable to locate element no such element gahhon 6 4,370 Feb-18-2019, 02:09 PM
Last Post: gahhon
  Change single element in 2D list changes every 1D element AceScottie 9 11,947 Nov-13-2017, 07:05 PM
Last Post: Larz60+
  common elements of a list Skaperen 5 9,379 Mar-22-2017, 10:13 AM
Last Post: buran
  Check to see if a string exactly matches an element in a list DBS 1 22,159 Nov-02-2016, 10:16 PM
Last Post: Ofnuts

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020