I have a list with different combinations, i.e:
list1 = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
I also have another list, in my case one looking like:
list2 = [1,1]
What I would like to do is to take the two values of list2, put them together as (1,1), and compare them with the elements in list1, then returning the index. My current attempt is looking like this:
def return_index(comb):
try:
return comb_leaves.index(comb)
except ValueError:
print("no such value")
Unfortunately, it cant find it, because it's not a sequence. Anyone with any good idea of how to fix this?
You are confusing "sequence" with "tuple". Lists and tuples are both sequences. Informally, a sequence is anything that has a length and supports direct indexing in addition to being iterable. A range object is considered to be a sequence too for example.
To create a two element tuple from any other sequence, use the constructor:
test_element = tuple(list_2)
list3 = tuple(list2)
print(list3 in list1) #Check if it exists.
Try this:
list1 = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
list2 = [1, 1]
def return_index(comb):
try:
return list1.index(tuple(comb))
except ValueError:
print("Item not found")
print(return_index(list2)) # 4
With this line:
list1.index(tuple(list2))
Convert list2 into a tuple from a list. list1's elements are tuples, so to make the comparison, list2 needs to be a tuple. tuple(list2) turns [1, 1] into (1, 1) (the same type as the elements of list1).
list1 = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
list2 = [1,1]
tup2 = tuple(list2)
list1.append(tup2)
print('list1:',list1)
print('index:', list1.index(tup2))
will give this:
list1: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (1, 1)]
index: 4
Not sure if unconditionally adding tup2 is what you want.
Maybe you ask for the index, if the 2nd list is in list1:
list1 = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]list2 = [1,1]
tup2 = tuple(list2)
if tup2 in list1:
print('index:', list1.index(tup2))
else:
print('not found')
That gives:
index: 4
the index function returns the first element that matches.
Related
according to #KellyBundy answer, I'd like to get rid of repeated self-values (2, 2), (0, 0)
and keep only either (2, 1) or (1, 2), keep only either (1, 0) or (0, 1) and get rid of repeated (0, 2)
[(0, 2), (2, 2), (2, 1), (1, 2), (2, 2), (0,2), (2, 2), (2, 1), (1, 0), (0, 0), (0, 1)]
out of this
from itertools import pairwise, chain
lis = [(0, [75, 1, 30]), (1, [41, 49, 55]), (2, [28, 53, 45])]
found = [*chain(*(pairwise(a) for *a, a[1:] in lis))]
print(found)
mylist = [(0, 2), (2, 2), (2, 1), (1, 2), (2, 2), (0,2), (2, 2), (2, 1), (1, 0), (0, 0), (0, 1)]
seen = set()
final = [(i,j) for i,j in mylist if i!=j and (i+j, abs(i-j)) not in seen and not seen.add((i+j, abs(i-j)))]
we filter on ((i+j), abs(i-j))
if you really need a one liner, we can use a lambda function
list(filter(lambda e, seen=set(): e[0]!=e[1] and (e[0]+e[1], abs(e[0]-e[1])) not in seen and not seen.add((e[0]+e[1], abs(e[0]-e[1]))), mylist))
i+j and abs(i-j) here are the sum and absolute difference. It makes the logic simpler since (x,y) and (y,x) have the same absolute difference and the same sum.
(i+j, abs(i+j)) is a tuple containing both the sum and absolute difference
seen here is a python set, which can be used to efficiently check if something already exists within it.
I have a list as follows:
mylist=[[(1, 1)], [(1, 1), (1, 2)], [(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]
Now, what I want is every element of this list is compared with all the other elements and if that element is the subset of the elements it is compared with, it should be popped. For example, [(1, 1)] is the subset of [(1, 1), (1, 2)] then [(1, 1)] should be popped from the list. Similarly, [(1, 1), (1, 2)] is the subset of [(1, 1), (1, 2), (1, 3)] then it should be popped also.
And in this case, we get the output as follows:
[[(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]
I tried searching for all the possible answers but none was aimed at this particular case.
So far I have tried the following method but of little use:
for i, e in enumerate(mylist):
mylist[i] = tuple(e)
mylist = list(set(mylist))
You need to remove any list from mylist where all the tuples in the list are present in another list in mylist. This is most easily done by assigning to a new list:
newlist = []
for i, lst in enumerate(mylist):
if not any(all(t in l for t in lst) for l in mylist[:i] + mylist[i+1:]):
newlist.append(lst)
Or as a list comprehension:
newlist = [lst for i, lst in enumerate(mylist) if not any(all(t in l for t in lst) for l in mylist[:i] + mylist[i+1:])]
In both cases, for your sample data the output is:
[
[(1, 1), (1, 2), (1, 3)],
[(1, 1), (1, 2), (1, 4)]
]
For larger lists this might become slow, in which case you can speed it up by first mapping the entries in mylist to sets:
mylist=[[(1, 1), (1, 2)], [(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)], [(1, 1)]]
mylist=list(map(set, (tuple(l) for l in mylist)))
newlist = [list(lst) for i, lst in enumerate(mylist) if not any(lst.issubset(l) for l in mylist[:i] + mylist[i+1:])]
You can use frozenset.issubset and do the comparaison like this example:
Thanks to #Nick suggestion, this is a more elaborated example:
mylist=[[(1, 1)], [(1, 1), (1, 2)], [(1, 1), (1, 2), (1, 3)], [(1, 1),
(1, 2), (1, 4)]]
out = []
for k, elm in enumerate(mylist):
for elm2 in mylist[:k] + mylist[k + 1:]:
if frozenset(elm).issubset(elm2):
break
else:
out.append(elm)
print(out)
Output:
[[(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]
Neither solutions from #Nick and #ChihebNexus are efficient.
The answer from #Nick requires a time complexity of O(m ^ 2 x n ^ 2), while #ChihebNexus's answer requires a time complexity of O(m ^ 2 x n), where m is the length of the input list and n is the average length of the sub-lists.
For an approach that requires just a time complexity of O(m x n), you can create a dict that maps each tuple item to a set of the sub-lists the item appears in, keeping in mind that these sub-lists need to be converted to tuples first to become hashable and be added to a set:
mapping = {}
for lst in mylist:
for item in lst:
mapping.setdefault(item, set()).add(tuple(lst))
so that with your sample input, mapping becomes:
{(1, 1): {((1, 1),),
((1, 1), (1, 2)),
((1, 1), (1, 2), (1, 3)),
((1, 1), (1, 2), (1, 4))},
(1, 2): {((1, 1), (1, 2), (1, 3)), ((1, 1), (1, 2)), ((1, 1), (1, 2), (1, 4))},
(1, 3): {((1, 1), (1, 2), (1, 3))},
(1, 4): {((1, 1), (1, 2), (1, 4))}}
And then with the mappings of items to their belonging sub-lists built, we can then iterate through the sub-lists again, and take the intersection of the sets of sub-lists that the items in the current sub-list map to, in order to find the sub-lists that contain all the items in the current sub-list. If there are more than one of such qualifying sub-lists, it means that the current sub-list is a subset of the other qualifying sub-lists, and that we can remove the current sub-list from the result by removing it from all the sets its items map to. The sub-lists that survive this process will be the ones we want in the output, which we can obtain by aggregating the sets with a union operation:
for lst in mylist:
if len(set.intersection(*map(mapping.get, lst))) > 1:
t = tuple(lst)
for item in lst:
mapping[item].remove(t)
print(set.union(*mapping.values()))
This outputs:
{((1, 1), (1, 2), (1, 3)), ((1, 1), (1, 2), (1, 4))}
You can convert it to a list of lists if you really want the exact data types in the question:
list(map(list, set.union(*mapping.values())))
which returns:
[[(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]
Say, I have a list like below:
[(2, 1), (1, 0), (1, 0), (1,0), (2,1), (2, 1)]
I want to remove duplicate consecutive tuples. So in above example, it should return:
[(2, 1), (1, 0), (2, 1)]
You can use itertools.groupby:
from itertools import groupby
x = [(2, 1), (1, 0), (1, 0), (1, 0), (2, 1), (2, 1)]
x_grouped = [i for i, j in groupby(x)]
# [(2, 1), (1, 0), (2, 1)]
You can use a generator that only yields elements that are not equal to the preceding one:
def filter_consecutive_duplicates(it):
prev = object() # sentinel object, won't be equal to anything else
for elem in it:
if elem != prev:
yield elem
prev = elem
Demo:
>>> list(filter_consecutive_duplicates([(2, 1), (1, 0), (1, 0),(1,0),(2,1), (2, 1)]))
[(2, 1), (1, 0), (2, 1)]
a=[(2, 1), (1, 0), (1, 0), (1,0), (2,1), (2, 1)]
a=[elem for count,elem in enumerate(a) if elem!=a[count-1] or count==0]
How about this list comprehension
I have a list of zipped pairs (for example A)
A = [(0, 0), (0, 1), (0, 6), (0, 7), (1, 3), (1, 1), (2, 2)]
What's the best way in which I can remove all pairs where the first and the second entries equal each other (and create a new list)?
In the above example (A), the pairs that I wish to remove are (0, 0), (1, 1) and (2, 2). In this example, I wish the new list to look like this.
A_new = [(0, 1), (0, 6), (0, 7), (1, 3)]
You can use simple list comprehension with if clause that returns True for all unequal pairs that you want to keep:
>>> A = [(0, 0), (0, 1), (0, 6), (0, 7), (1, 3), (1, 1), (2, 2)]
>>> [(x, y) for x, y in A if x != y]
[(0, 1), (0, 6), (0, 7), (1, 3)]
using filter, it takes a judge function as first parameter to tell what element to keep and the iterable list as second parameter, lambda defines an anonymous function.
A_new = filter(lambda x: x[0] != x[1], A)
you can do it with list comprehension:
a = [(0, 0), (0, 1), (0, 6), (0, 7), (1, 3), (1, 1), (2, 2)]
final = [k for k in a if k[0] != k[1]]
Output:
print(final)
>>> [(0, 1), (0, 6), (0, 7), (1, 3)]
Basically I need lists of rows that go like this:
[0,0]
[1,0],[0,1]
[2,0],[1,1],[0,2]
[3,0],[2,1],[1,2],[0,3]
[4,0],[3,1],[2,2],[1,3],[0,4]
up to an arbitrary number of elements and then back down
[4,1],[3,2],[2,3],[1,4]
[4,2],[3,3],[2,4]
[4,3],[3,4]
[4,4]
I'm just wanting all of these pairs in one large list of lists, so I can iterate over the pairs in the order they appear above for isometric rendering.
the output would look like this
[ [ (0,0) ], [ (1,0),(0,1) ], [ (2,0), (1,1), (0,2) ]....]etc
It's not entirely clear what generalization you're looking for, but IIUC there are lots of ways you can do it. One is to build each sublist from the previous list (adding one to each subelement and avoiding duplicates), but another is to work directly from the arithmetic:
def sherwood(n):
N = 2*n+1
for i in range(N):
low, high = max(0, i-n), min(i, n)
w = list(range(low, high+1))
yield zip(w[::-1], w)
gives me
>>> out = list(sherwood(2))
>>> for x in out: print(x)
[(0, 0)]
[(1, 0), (0, 1)]
[(2, 0), (1, 1), (0, 2)]
[(2, 1), (1, 2)]
[(2, 2)]
>>> out = list(sherwood(4))
>>> for x in out: print(x)
[(0, 0)]
[(1, 0), (0, 1)]
[(2, 0), (1, 1), (0, 2)]
[(3, 0), (2, 1), (1, 2), (0, 3)]
[(4, 0), (3, 1), (2, 2), (1, 3), (0, 4)]
[(4, 1), (3, 2), (2, 3), (1, 4)]
[(4, 2), (3, 3), (2, 4)]
[(4, 3), (3, 4)]
[(4, 4)]
def create_lists(max_num):
retlist = []
for i in range(max_num+1):
i_list = []
for j in range(i, -1, -1):
i_list.append((j, i-j))
retlist.append(i_list)
for i in range(1, max_num+1):
i_list = []
for j in range(i, max_num+1):
i_list.append((max_num+i-j, j))
retlist.append(i_list)
return retlist