Subtract two lists of tuples from each other - python

I have the these two lists and I need to subtract one from the other but the regular "-" won't work, neither will .intersection or XOR (^).
A = [(0, 1)]
B = [(0, 0), (0,1), (0, 2)]
Essentially what I want is:
B - A = [(0, 0), (0, 2)]

You can use list comprehension to solve this problem:
[item for item in B if item not in A]
More discussion can be found here

If there are no duplicate tuples in B and A, might be better to keep them as sets, and use the difference of sets:
A = [(0, 1)]
B = [(0, 0), (0,1), (0, 2)]
diff = set(B) - set(A) # or set(B).difference(A)
print(diff)
# {(0, 0), (0, 2)}
You could perform other operations like find the intersection between both sets:
>>> set(B) & set(A)
{(0, 1)}
Or even take their symmetric_difference:
>>> set(B) ^ set(A)
{(0, 0), (0, 2)}

You can do such operations by converting the lists to sets. Set difference:
r = set(B)-set(A)
Convert to list if necessary: list(r)
Working on sets is efficient compared to running "in" operations on lists: using lists vs sets for list differences

Related

Zip two int lists with all possible sign combinations

Say I have two lists of ints:
a = [1,2]
b = [3,4]
And I want to end up with a list of tuples like this:
[(1,3),(2,4),(-1,-3),(-2,-4),(1,-3),(2,-4),(-1,3),(-2,4)]
That is, I'm zipping the nth element of a with the nth element of b, but using all possible positive/negative sign combinations. What's the most elegant way to do this?
A not elegant way would be to create two further lists like this
a_neg = [-n for n in a]
b_neg = [-n for n in b]
then zip a with b, a_neg with b_neg, a with b_neg, and a_neg with b, and combine the results. This works fine but is unsatisfying. Is there a simpler way to do this?
I wouldn't try to be fancy with list comprehensions and just use a for loop
for idx, i in enumerate(a):
c.extend([(i, b[idx]), (-i, b[idx]), (i, -b[idx]), (-i, -b[idx])])
>>> c
[(1, 3), (-1, 3), (1, -3), (-1, -3), (2, 4), (-2, 4), (2, -4), (-2, -4)]
Or using a zip
for x,y in zip(a,b):
c.extend([(x,y), (-x, y), (x,-y), (-x, -y)])
Use this answer and just apply it across the zipped sequence, flattening the result into a single list.
from itertools import product
def sign_combinations(nums):
return product(*((x, -x) for x in nums))
a = [1,2]
b = [3,4]
print([c for t in zip(a, b) for c in sign_combinations(t)])

Generating 2D grid indices using list comprehension

I would like to store the row and column indices of a 3 x 3 list in list. It should look like the following:
rc = [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]
How can I get this list using a list comprehension in Python?
Some consider multiple for loops inside a list comprehension to be poor style. Use itertools.product() instead:
from itertools import product
list(product(range(3), repeat=2))
This outputs:
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
How about:
[(x, y) for x in range(3) for y in range(3)]
If I understand correctly, and the input is A, the B can be output as follows:
A = [[1,2,3],[4,5,6],[7,8,9]]
B =[(A[i], A[j]) for i in range(3) for j in range(3)]

Remove bracket in a list of tuples in tuples

I would like to remove the bracket of a tuples who belong to tuples within a list:
Here's an example:
List_1 = [(0, (1, 1)),
(0, (1, 2)),
(0, (1, 3))]
And the expected output should look like this:
list_2 = [(0, 1, 1),
(0, 1, 2),
(0, 1, 3)]
I tried this:
for element in List_n_d1d2:
newlist = (element[0], element[1])
But ended up with the same output... Could you please help me, thank you !
Use the * spread operator to expand the tuple into separate elements.
list_2 = [(a, *b) for a, b in list_1]
A simple comprehension would be:
[(a,) + b for a,b in List_1]

How to sort a Python List with a runtime defined amount of priorities

I want to find a way in python to sort tuples prioritizing the lowest index elements. Is this possible in python? I'm overgeneralizing a different problem I have with sorting a list with priorities over values that I don't know before hand.
For example, if I know the length of my tuple I could do this
sorted(myList, key=lambda n: (n[0],n[1]))
here I know that myList is made up of tuples with 2 elements, but I had to hard code it. Can I generalize this to sort based on priority for a tuple with x elements? Here's a pseudo code idea in python,
sorted(myList, key=lambda n: n[i] for i in range(len(n)))
sorted does this by default; you don't even need a key argument.
>>> k = [(0, 1), (1, 1), (1, 0), (0, 0)]
>>> sorted(k)
[(0, 0), (0, 1), (1, 0), (1, 1)]

Weed out combinations with certain condition

I am a newbee in python and programing, I am trying to come up with combinations and weed out combinations with certain conditions.
So in the case below, I have tried to generate all possible combinations between 1-100. But I don't know where to go after this.
import itertools
i_list = []
for i in range (1, 101):
i_list.append(i)
comb = itertools.combinations(i_list,2)
for combinations in list(comb):
print (combinations)
This runs fine and will generate a list from 1-100, and give me an output of
(1,2) (1,3).........(98,99) (98,100) (99,100)
Now my goal is to weed out the combinations with a difference < 5, so for example: (1,2) the difference is less than 5, so it should not be outputted. (1,8) the difference is greater than 5, so it should be outputted. I hope that make sense.
Can anyone guide me through the thought process and suggest an easy approach?
You can use itertools.filterfalse for this and then iterate over the result.
Also, with iterators, you want to wait until you really need a list before you convert to a list with list(). There's no reason to ever do that in this case because you are always iterating. This allows you to work with very large sets without taking up the memory and time of running through the iterator just to make a list to then iterate the list:
from itertools import combinations, filterfalse
comb = combinations(range(1, 101),2)
filtered = filterfalse(lambda x: abs(x[0] - x[1]) < 5, comb)
for combinations in filtered:
print (combinations)
The iterators produced by range(), combinations and fitleredfalse are all lazy, so they never start evaluating until you start looping over them. This allows you to defer any work until it needs to be done or to iterate over part of a large set without calculating the entire thing.
You can use a list comprehension to restrict the generated values to be kept inside the list:
from itertools import combinations
comb = [ x for x in combinations(range(1,101),2) if x[1]-x[0]>4 ]
print (comb)
Output:
[(1, 6), (1, 7), (1, 8), ... snipp ..., (93, 99), (93, 100), (94, 99), (94, 100), (95, 100)]
combinations respects the order of numbers so no abs() around x[1]-x[0] needed - range itself is a sequence and your resulting list weeds out all numbers you do not want due to the if x[1]-x[0]>4 condition.
This should accomplish what you are asking:
>>> import itertools
>>> combinations = itertools.combinations(range(1, 101), 2)
>>> generator = ((a, b) for a, b in combinations if b - a >= 5)
>>> for pair in generator:
print(pair, end=' ')
(1, 6) (1, 7) (1, 8) (1, 9) (1, 10) (1, 11) (1, 12) (1, 13) (1, 14) (1, 15) ...
Alternatively, you can try this instead to do the exact same thing:
>>> generator = ((a, b) for a in range(1, 96) for b in range(a + 5, 101))
>>> for pair in generator:
print(pair, end=' ')
(1, 6) (1, 7) (1, 8) (1, 9) (1, 10) (1, 11) (1, 12) (1, 13) (1, 14) (1, 15) ...

Categories

Resources