Say I have list1 = [1,2,3,4] and list2 = [5,6,7,8]. How would I compare the first element, 1, in list1 with the first element, 5, in list2? And 2 with 6, 3 with 7, and so on.
I'm trying to use a for loop for this, but I'm not sure how to do it. I understand that doing for x in list1 just checks an element x to all elements in list1, but I don't know how to do it when comparing two lists the way I described.
You can traverse both lists simultaneously using zip:
for (x, y) in zip(list1, list2): do_something
The 'zip' function gives you [(1,5), (2,6), (3,7), (4,8)], so in loop iteration N you get the Nth element of each list.
The default comparison operators compare lists in lexicographical order. So you can say things like:
>>> [1, 2, 3, 4] < [5, 6, 7, 8]
True
If instead you want to compute the elementwise comparison, you can use map and cmp (or any other operator:
>>> map(cmp, [1, 2, 3, 4], [5, 6, 7, 8])
[-1, -1, -1, -1]
If your result is going to be a new list, then you can use a list comprehension:
new_list = [ some_function(i, j) for i, j in zip(list1, list2) ]
Here's a real example of the above code:
>>> list1 = [1, 2, 3, 4]
>>> list2 = [1, 3, 4, 4]
>>> like_nums = [ i == j for i, j in zip(list1, list2) ]
>>> print like_nums
[True, False, False, True]
This will make a list of bools that show whether items of the same index in two lists are equal to each other.
Furthermore, if you use the zip function, there is a way to unzip the result when you are done operating on it. Here's how:
>>> list1 = [1, 2, 3, 4]
>>> list2 = [1, 3, 4, 4]
>>> new_list = zip(list1, list2) # zip
>>> print new_list
[(1, 1), (2, 3), (3, 4), (4, 4)]
>>> newlist1, newlist2 = zip(*new_list) # unzip
>>> print list(newlist1)
[1, 2, 3, 4]
>>> print list(newlist2)
[1, 3, 4, 5]
This could be useful if you need to modify the original lists, while also comparing the elements of the same index in some way.
Related
I am doing an assignment, which requires me to do a code walkthrough. I would like to have a brief description on how set().union(*list1) works so i can answer during my walkthrough.
list1 = [[1,2,3],[1,2,3,5,8]]
x = set().union(*list1)
print(list(x))
#output = [1, 2, 3, 5, 8]
From the docs: https://docs.python.org/3/library/stdtypes.html#frozenset.union
union(*others)
set | other | ...
Return a new set with elements from the set and all others.
Also *list is called list unpacking, where we get the two sublists inside the list
In [37]: list1 = [[1,2,3],[1,2,3,5,8]]
In [38]: print(*list1)
[1, 2, 3] [1, 2, 3, 5, 8]
So the code you ran essentially creates a union of all the sublists within the list x, and since you know that the union of set [1,2,3] and [1,2,3,5,8] is [1,2,3,5,8], hence the expected result.
Note that this is equivalent to list(set([1,2,3]).union(set([1,2,3,5,8]))) where we are doing a.union(b), a and b being sets
In [31]: list1 = [[1,2,3],[1,2,3,5,8]]
...:
...: x = set().union(*list1)
In [32]: print(list(x))
[1, 2, 3, 5, 8]
In [33]: print(list(set([1,2,3]).union(set([1,2,3,5,8]))))
[1, 2, 3, 5, 8]
Adding to this, a better approach to do union or even intersection might be to convert the list of lists to a list of sets, using map(set,list1), unrolling the sets and then doing the operations
In [39]: list1 = [[1,2,3],[1,2,3,5,8]]
In [40]: print(set.intersection(*map(set,list1)))
{1, 2, 3}
In [41]: print(set.union(*map(set,list1)))
{1, 2, 3, 5, 8}
I want to check whether row 1 is equal to column one and row two is equal to column 2 and so on. If a matrix is equal to its transpose.
I tried to solve the problem using the following code, but the function is returning none. Can some one help me with this
x = [[1, 2, 3],
[2, 3, 4],
[3, 4, 1]]
def rows(matrix):
list = [val for val in matrix]
list1 = [i for i in zip(*matrix)]
if list == list1:
return True
else:
return False
rows(x)
zip returns tuples, not lists:
>>> [val for val in x]
[[1, 2, 3], [2, 3, 4], [3, 4, 1]]
>>> [i for i in zip(*x)]
[(1, 2, 3), (2, 3, 4), (3, 4, 1)]
And they don't compare equal to each other:
>>> [1,2,3] == (1,2,3)
False
Instead, you can simply return the results of the comparison after converting to lists:
>>> x == [list(i) for i in zip(*x)]
True
Use map to map the sublists to tuples and compare, mapping to tuple shoud also be more efficient than changing tuples to lists:
def rows(matrix):
return zip(*matrix) == map(tuple, matrix)
The zip function returns a list of tuples:
>>> x = [[1, 2, 3],
[2, 3, 4],
[3, 4, 1]]
>>> zip(*x)
[(1, 2, 3), (2, 3, 4), (3, 4, 1)]
>>> x == zip(*x)
False
A list isn't equal to a tuple, even if it has the same elements. A list of lists isn't equal to a list of tuples, even if the inner lists/tuples contain the same elements. You can do what you want easily, and you were close!
>>> x == [list(i) for i in zip(*x)]
True
You can understand what is wrong with your program by running this:
x = [[1, 2, 3],[2, 3, 4],[3, 4, 1]]
def rows(matrix):
list = [val for val in matrix]
list1 = [i for i in zip(*matrix)]
print list
print list1
if list == list1:
return True
else:
return False
print rows(x)
Here print list prints list of lists, while print list1 prints list of touples.
Since lists and touples are different, the program returns False.
I am trying to create a function that can do this.
>>> rearrange_list([1,2,3],[4,5,6])
[[1,4],[2,5],[3,6]]
So far what I have is
def rearrange_list(my_list):
i = 0
n = 0
new_list = []
for i in range(0, len(my_list[n])):
for n in range(0,len(my_list)):
new_list += [my_list[n][i]]
print(new_list)
n += 1
return new_list
but this code returns [1, 4, 2, 5, 3, 6], a single list instead of
a list of lists like I want it to and I can't seem to figure out how to make the
function output a list of lists based on the index of the list inside the list.
Use zip like so:
zip(list_a, list_b)
You can use zip and a list comprehension:
>>> def rearrange_lists(a, b):
... return [list(x) for x in zip(a, b)]
...
>>> rearrange_lists([1,2,3], [4,5,6])
[[1, 4], [2, 5], [3, 6]]
>>>
Note that the above function only handles two lists. If you want to handle any number of lists, you can use this:
>>> def rearrange_lists(*lsts):
... return [list(x) for x in zip(*lsts)]
...
>>> rearrange_lists([1,2,3], [4,5,6], [7,8,9])
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
>>>
Use zip() instead:
>>> zip([1,2,3], [4,5,6])
[(1, 4), (2, 5), (3, 6)]
or, for your specific varargs version:
>>> lsts = ([1,2,3], [4,5,6])
>>> zip(*lsts)
[(1, 4), (2, 5), (3, 6)]
or map the results to lists if tuples won't do:
map(list, zip([1,2,3], [4,5,6])) # Python 2
[list(t) for t in zip([1,2,3], [4,5,6])] # Python 2 and 3
As a replacement for your function:
def rearrange_list(*my_lists):
return [list(t) for t in zip(*my_lists)]
I have a list of N lists, each sub-list containing M elements.
How do I create a list of M lists with N elements each, containing the n-th elements from the initial lists?
Let's say I have this
myList = [[1, 2, 3],[4, 5, 6]]
I want to have
[[1, 4],[2, 5],[3, 6]]
Performance is also important. I have sublists of millions of elements (though, one dimension will always be small: like 1.000.000 x 8 )
This will give tuples, but it's trivial to extend this to contain lists:
zip(*myList)
i.e.
[list(i) for i in zip(*myList)]
Use
myList = [[1, 2, 3],[4, 5, 6]]
zip(*myList )
>>> lst = [[1, 2, 3], [4, 5, 6]]
>>> zip(*lst)
[(1, 4), (2, 5), (3, 6)]
zip returns a list in Python 2, but an iterator in Python 3, which you have to convert to a list if you need to (list(zip(lst)))
See also: Matrix Transpose in Python, Transpose/Unzip Function (inverse of zip)?
What zip(*lst) does is unpacks the elements of lst using the * operator into separate arguments of the zip function.
We know what happens when we put two lists in:
>>> zip([1, 2, 3], [4, 5, 6])
[(1, 4), (2, 5), (3, 6)]
So if we have a list containing those two lists, the * will unpack the list to form two separate arguments - the equivalent of the above call.
>>> zip(*[[1, 2, 3], [4, 5, 6]])
[(1, 4), (2, 5), (3, 6)]
Maybe with the help of itertools.izip()
itertools.izip(*myList)
To create lists from this iterator do the following:
map(list, itertools.izip(*myList))
Since you mentioned efficiency, I tried these with PyPy and somewhere around 100x1000 they start to be better than zip (on CPython however they are worse):
myList = [[1, 2, 3],[4, 5, 6]]
newList = [[] for _ in xrange(len(myList[0]))]
for innerList in myList:
for elIdx in xrange(len(innerList)):
newList[elIdx].append(innerList[elIdx])
print newList
And my first attempt (which is worse), but still better then zip on PyPy:
newList = [[None for i in xrange(len(myList))] for j in xrange(len(myList[0]))]
for i in xrange(len(myList)):
for j in xrange(len(myList[i])):
newList[j][i] = myList[i][j]
print newList
I have a list and I want to use a certain function only on those entries of it that fulfills a certain condition - leaving the other entries unmodified.
Example: Say I want to multiply by 2 only those elements who are even.
a_list = [1, 2, 3, 4, 5]
Wanted result:
a_list => [1, 4, 3, 8, 5]
But [elem * 2 for elem in a_list if elem %2 == 0] yields [4, 8] (it acted as a filter in addition).
What is the correct way to go about it?
Use a conditional expression:
[x * 2 if x % 2 == 0 else x
for x in a_list]
(Math geek's note: you can also solve this particular case with
[x * (2 - x % 2) for x in a_list]
but I'd prefer the first option anyway ;)
a_list = [1, 2, 3, 4, 5]
print [elem*2 if elem%2==0 else elem for elem in a_list ]
or, if you have a very long list that you want to modify in place:
a_list = [1, 2, 3, 4, 5]
for i,elem in enumerate(a_list):
if elem%2==0:
a_list[i] = elem*2
so, only the even elements are modified
You could use lambda:
>>> a_list = [1, 2, 3, 4, 5]
>>> f = lambda x: x%2 and x or x*2
>>> a_list = [f(i) for i in a_list]
>>> a_list
[1, 4, 3, 8, 5]
Edit - Thinking about agf's remark I made a 2nd version of my code:
>>> a_list = [1, 2, 3, 4, 5]
>>> f = lambda x: x if x%2 else x*2
>>> a_list = [f(i) for i in a_list]
>>> a_list
[1, 4, 3, 8, 5]