The problem is: swapping the second element between two tuples meeting all the following criteria: consisting of two ints, each in range(5), elements in same positions aren't equal
If they are two lists I can simply use variable swapping with indexing but tuples are immutable so I unpacked the two tuples into a single list and unpacked that list into four variables and reordered the variables...
Example Code
(See the initial values the variables are declared with, the printed values are the intended result.)
a, b = [1,2], [3,4]
a[1], b[1] = b[1], a[1]
print(a)
print(b)
l1, l2 = (1,2), (3,4)
a, b, c, d = [*l1, *l2]
print((a, d))
print((c, b))
In [161]: a, b = [1,2], [3,4]
...: a[1], b[1] = b[1], a[1]
...: print(a)
...: print(b)
...:
...: l1, l2 = (1,2), (3,4)
...: a, b, c, d = [*l1, *l2]
...: print((a, d))
...: print((c, b))
[1, 4]
[3, 2]
(1, 4)
(3, 2)
I don't want to cast the tuples into lists, I wonder if there is a better way to swap the second element between the two tuples?
You're right that the tuples are immutable, and you won't be able to get around creating new tuples. If you just want to do this without using unpacking notation, you could do something like
l1, l2 = (1,2), (3,4)
a = (l1[0],l2[1])
b = (l2[0],l1[1])
If speed is a concern here, running this with pypy will be very efficient.
Try this:
t = (1, 2)
swapped = t[::-1]
# true
assert type(swapped) == tuple
assert swapped == (2, 1)
Related
I am quite new to Sympy (running with Python 3).
Given two lists of integers, in general not of equal lengths and whose elements might repeat, I need to eliminate all pairs of equal elements between the two lists.
For example, given
List_a=[1, 2, 3, 4, 4], List_b=[0, 2, 2, 4]
I shall eliminate the pairs (2,2) and (4,4) and output
List_ar=[1,3,4], List_br=[0,2]
If the two lists are equal I shall get two empty lists as output.
I have been trying to compare the lists element by element ( "for" and "while" loops) and when found equal to delete the pair from both lists. Upon that to repeat the procedure on the reduced lists till no deletion is made.
But lacking of a "goto" control I do not know how to handle the variable length lists.
Thanks for helping.
I you convert them to multiset you can compare the counts of common keys:
>>> from sympy.utilities.iterables import multiset
>>> ma = multiset(lista)
>>> mb = multiset(listb)
>>> for k in set(ma) & set(mb):
... n = min(ma[k],mb[k])
... ma[k] -= n
... mb[k] -= n
...
>>> lista = [i for k in ma for i in [k]*ma[k]]
>>> listb = [i for k in mb for i in [k]*mb[k]]
You could also treat this like a merge sort but the above is direct.
A general Python solution:
def g(a, b):
def ensure2(xs):
ys = [list(x) for x in xs]
if ys == []:
return [[], []]
else:
return ys
n = min(len(a), len(b))
c, d = ensure2(
zip(*
filter(lambda x: x[0] != x[1],
zip(a, b))))
return c + a[n:], d + b[n:]
a = [1,2,3,4,4]
b = [0,2,2,4]
c = [0,2,2,4]
d = []
# two different lists
ar, br = g(a, b)
print(ar) # [1, 3, 4]
print(br) # [0, 2]
# two identical lists
br, cr = g(b, c)
print(br) # []
print(cr) # []
# one empty list
ar, dr = g(a, d)
print(ar) # [1, 2, 3, 4, 4]
print(dr) # []
Use zip() to create the pairs
Use filter() to remove pairs with equal elements
Use zip(*...) to split the remaining pairs back to two lists
Use ensure2() to guard against empty lists
Use + list[n:] to append excessive elements back to the originally longer list
Example, I have the following lists in Python
A = [1,2,3]
B = [4,5,6]
I would need to create a new list C such that the elements should be paired as a separate lists based on their index numbers. i.e., C = [[[1,4],[2,5],[3,6]], [[1,4],[2,5],[3,6]]]
I have written a code to that but it is purely structured. Can you please provide if there is any better way other than the below code?
A = [1,2,3]
B = [4,5,6]
D = [a,b,c]
E = [d,e,f]
C = []
list = []
for i in range(len(A)):
list.append([A[i],B[i]])
C.append(list)
list = []
for i in range(len(D)):
list.append([D[i],E[i]])
C.append(list)
I have to repeat this code if I have multiple cases similar to the above one in my code. Which is poor in structuring.
Can someone suggest any better method for the problem?
You can use zip, convert that to list
list(zip(a,b))
which will give list of tuples. If you want list of lists, you can go:
[[i,j] for i,j in zip(a,b)]
You can try something like this in one line.
C = [[A[i],B[i]] for i in range(len(A))]
Be careful if A and B don't have the same length though!
Your problem has a simple solution found in Python's built-in functions,
The 'zip' function takes 2 arguments (iterables) and return a single iterator.
Here is an example code:
a = [1, 2, 3]
b = [4, 5, 6]
c = list(zip(a, b))
# c -> [(1, 4), (2, 5), (3, 6)]
# if you want the elements to be list instead of tuple you can do
c = [[i, j] for i,j in zip(a, b)]
# c -> [[1, 4], [2, 5], [3, 6]]
you can use zip for this
c= zip(a,b)
c=list(c)
if you convert in set then
c=set(c)
Using numpy, the following would be efficient.
import numpy as np
A = [1,2,3]
B = [4,5,6]
a = np.array(A)
b = np.array(B)
c = np.vstack((a, b)).T
print c
C = c.tolist()
print C
lower case letters are all numpy arrays, upper case are python arrays
a = [2,7,9]
b = [[7,9],[1,2],[2,9]]
How many pairs in list [a] matches pair tuple [b]
Notice both pair [7,9] and [2,9] in list [a]. Even though pair [1,2] contains a digit of 2, it doesn't get counted because both digits are not in list [a].
The return value should be 2, the len of the matching pairs.
len(filter(lambda l:if_in(b,l),a))
Need help creating a if_in function or a simpler way of writing this function all in one. How can I make this function work no matter the size of a or b.
Make a a set and use set.issuperset, checking if a is a superset of each sublist:
a = [2,7,9]
b = [[7,9],[1,2],[2,9]]
st = set(a)
print(sum(st.issuperset(sub) for sub in b))
2
You can go two ways, either making all the sublists sets or as above just make a set, when a is a superset of a sublist then the sublist is a subset of a:
In [6]: a = [2,7,9]
In [7]: b = [[7,9],[1,2],[2,9]]
In [8]: st = set(b[0])
In [9]: st.issubset(a)
Out[9]: True
In [10]: st = set(b[1])
In [11]: st.issubset(a)
Out[11]: False
In [13]: st = set(a)
In [13]: st.issuperset(b[0])
Out[13]: True
In [14]: st.issuperset(b[1])
Out[14]: False
Obviously as there are only a few numbers in your a list it make more sense to make a set from a and use superset.
If you want to work with the subsets of a, you can use itertools.combinations(iterable, r).
Quoting the docs, returns r length subsequences of elements from the input iterable.
from itertools import combinations
a = [2, 7, 9]
b = [(7, 9), (1, 2), (2, 9)]
# combinations returns a collection of tuples
# so changed your b items to tuples.
len(filter(lambda x: x in b, combinations(a ,2))
pt1 and pt2 are two tuple made up of ints.
pairs = zip(pt1, pt2)
sum_sq_diffs = sum((a - b)**2 for a, b in pairs)
return (sum_sq_diffs)
My question concerns the second line. What are a and b? If you print them by doing:
print list((a,b) for a, b in pairs))
you get [(pt1x,pt2x), (pt1y, pt2y)]
If I take two tuples and subtract them, you get an error. So how come sum_sq_diffs = sum((a - b)**2 for a, b in pairs) doesn't result in an error? It seems a is a tuple and b is a tuple.
You understand that pairs is a list of tuples.
Now, the second line is a list comprehension which is the equivalent of
sum_sq_diffs = 0
for a, b in pairs:
sum_sq_diffs += (a - b)**2
Now, while iterating through the individual elements, python would do a "tuple unpacking" for you , and extracts the (x, y) to local variables a and b respectively.
You can read more on tuple unpacking here
This is called, appropriately enough, tuple unpacking. Tuple unpacking requires that the list of variables on the left has the same number of elements as the length of the tuple. Note that multiple assignment is really just a combination of tuple packing and tuple unpacking!
Here is a quick demo which should demonstrate this:
>>> pt1 = [1, 2, 3]
>>> pt2 = [4, 5, 6]
>>> pairs = zip(pt1, pt2)
>>> pairs
[(1, 4), (2, 5), (3, 6)]
>>> sum_sq_diffs = sum((a - b)**2 for a, b in pairs)
>>> sum_sq_diffs
27
>>> sum_sq_diffs_2 = 0
>>> for a, b in pairs:
... print a, b
... sum_sq_diffs_2 += (a - b)**2
...
1 4
2 5
3 6
>>> sum_sq_diffs_2
27
>>>
pairs should be a list of tuples.
a, b should unpack those tuples, one at a time. So they should be scalars.
There is much to like about list comprehensions and generator expressions. One thing I don't like about them, is you tend to end up rewriting them as loops when you have a question about how they are behaving.
But I do suggest rewriting your comprehension as a loop, and inserting a print(a,b) or print a, b. It may help.
Given two lists of equal length, is there a simpler or preferred way to iterate over two lists of equal length and append the maximum of each pair of elements to a new list? These are the two methods I know of.
import itertools
a = [1,2,3,4,5]
b = [1,1,6,3,8]
m1 = list()
m2 = list()
for x, y in zip(a, b):
m1.append(max(x, y))
for x in itertools.imap(max, a, b):
m2.append(x)
Both of these result in [1, 2, 6, 4, 8], which is correct. Is there a better way?
map(max, a, b)
[max(x, y) for x, y in zip(a, b)]
You could do it like:
a = [1,2,3,4,5]
b = [1,1,6,3,8]
m3 = [max(x,y) for (x,y) in zip(a,b)]
or even
m4 = map(max, zip(a,b))
In Python3, map() no longer returns a list, so you should use the list comprehension or
list(map(max, a, b))
if you really need a list and not just an iterator