Posts: 11
Threads: 4
Joined: Mar 2020
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.
Posts: 6,779
Threads: 20
Joined: Feb 2020
Nov-01-2020, 04:14 PM
(This post was last modified: Nov-01-2020, 04:23 PM by deanhystad.)
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
Posts: 11
Threads: 4
Joined: Mar 2020
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.
Posts: 6,779
Threads: 20
Joined: Feb 2020
Nov-01-2020, 05:32 PM
(This post was last modified: Nov-01-2020, 08:34 PM by deanhystad.)
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]
Posts: 6,779
Threads: 20
Joined: Feb 2020
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))
Posts: 1,358
Threads: 2
Joined: May 2019
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)])
Posts: 6,779
Threads: 20
Joined: Feb 2020
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
Posts: 1,950
Threads: 8
Joined: Jun 2018
Nov-02-2020, 09:18 AM
(This post was last modified: Nov-02-2020, 09:18 AM by perfringo.)
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  .
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.
Posts: 6,779
Threads: 20
Joined: Feb 2020
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.
Posts: 566
Threads: 10
Joined: Apr 2017
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
|