For-loop over several variables from a single list - python

I'm trying to create a loop like this
newList = [a + b for a,b in list[::2], list[1::2]]
meaning, take two consecutive entries from a list, do something with them and put the into a new list.
How would that work?

You want to zip your two newly created lists:
newList = [a + b for a,b in zip(list[::2], list[1::2])]
You also do this in a somewhat more memory-efficient manner by using an iterator:
it = iter(list)
newList = [a + b for a, b in zip(it, it)]
or even more efficiently* by using the izip function, which returns an iterator:
import itertools
it = iter(list)
newList = [a + b for a, b in itertools.izip(it, it)]
* at least under Python 2.x; in Python 3, as I understand it, zip itself returns an iterator.
Note that you really should never call a variable list as this clobbers the builtin list constructor. This can cause confusing errors and is generally considered bad form.

>>> L=range(6)
>>> from operator import add
>>> map(add, L[::2], L[1::2])
[1, 5, 9]
alternatively you could use an iterator here
>>> L_iter = iter(L)
>>> map(add, L_iter, L_iter)
[1, 5, 9]
since you pass the same iterator twice, map() will consume two elements for each iteration
Another way to pass the iterator twice is to build a list with a shared reference. That avoids the temporary variable
>>> map(add, *[iter(L)]*2)
[1, 5, 9]
of course you can replace add with your own function
>>> def myfunc(a,b):
... print "myfunc called with", a, b
... return a+b
...
>>> map(myfunc, *[iter(L)]*2)
myfunc called with 0 1
myfunc called with 2 3
myfunc called with 4 5
[1, 5, 9]
And it's easy to expand to 3 variables or more
>>> def myfunc(*args):
... print "myfunc called with", args
... return sum(args)
...
>>> map(myfunc, *[iter(L)]*3)
myfunc called with (0, 1, 2)
myfunc called with (3, 4, 5)
[3, 12]

Zip and Map come in handy here.
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> list(zip(a, b))
[(1, 4), (2, 5), (3, 6)]
>>> list(map <operation>, (zip(a, b)))
>>> ...
Or in your case,
>>> list(map(lambda n: n[0] + n[1], (zip(a, b))))
[5, 7, 9]
There's definitely a better way to pass the plus operation to the map. Feel free to add to it, anyone!

Related

weird behavior of list.append( ) function [duplicate]

I was going through the topic about list in Learning Python 5E book.
I notice that if we do concatenation on list, it creates new object. Extend method do not create new object i.e. In place change.
What actually happens in case of Concatenation?
For example
l = [1,2,3,4]
m = l
l = l + [5,6]
print l,m
#output
([1,2,3,4,5,6], [1,2,3,4])
And if I use Augmented assignment as follows,
l = [1,2,3,4]
m = l
l += [5,6]
print l,m
#output
([1,2,3,4,5,6], [1,2,3,4,5,6])
What is happening in background in case of both operations?
There are two methods being used there: __add__ and __iadd__. l + [5, 6] is a shortcut for l.__add__([5, 6]). l's __add__ method returns the result of addition to something else. Therefore, l = l + [5, 6] is reassigning l to the addition of l and [5, 6]. It doesn't affect m because you aren't changing the object, you are redefining the name. l += [5, 6] is a shortcut for l.__iadd__([5, 6]). In this case, __iadd__ changes the list. Since m refers to the same object, m is also affected.
Edit: If __iadd__ is not implemented, for example with immutable types like tuple and str, then Python uses __add__ instead. For example, x += y would be converted to x = x + y. Also, in x + y if x does not implement __add__, then y.__radd__(x), if available, will be used instead. Therefore x += y could actually be x = y.__radd__(x) in the background.
You can understand this better by inspecting the objects referenced in memory. Lets use id for the inspection
In the first case:
>>> l = [1,2,3,4]
>>> id(l)
4497052232
>>> m = l
>>> id(m)
4497052232
>>> l = l + [5,6]
>>> id(l)
4497052448
>>> print l, id(l), m, id(m)
[1, 2, 3, 4, 5, 6] 4497052448 [1, 2, 3, 4] 4497052232
>>>
Notice that l = l + [5,6] creates a new object in memory, and l references that.
In the second case:
>>> l = [1,2,3,4]
>>> id(l)
4497052520
>>> m = l
>>> id(m)
4497052520
>>> l += [5,6]
>>> id(l)
4497052520
>>> print l, id(l), m, id(m)
[1, 2, 3, 4, 5, 6] 4497052520 [1, 2, 3, 4, 5, 6] 4497052520
>>>
l += [5,6] references to the same object in memory. Hence the result.
So, basically += is the equivalent of inplace add.. More on this can be read here

Python appending two returns to two different lists

I am wanting to append two returned lists to two different lists such as
def func():
return [1, 2, 3], [4, 5, 6]
list1.append(), list2.append() = func()
Any ideas?
You'll have to capture the return values first, then append:
res1, res2 = func()
list1.append(res1)
list2.append(res2)
You appear to be returning lists here, are you certain you don't mean to use list.extend() instead?
If you were extending list1 and list2, you could use slice assignments:
list1[len(list1):], list2[len(list2):] = func()
but this is a) surprising to newcomers and b) rather unreadable in my opinion. I'd still use the separate assignment, then extend calls:
res1, res2 = func()
list1.extend(res1)
list2.extend(res2)
Why not just storing the return values?
a, b = func() #Here we store it in a and b
list1.append(a) #append the first result to a
list2.append(b) #append the second one to b
With this, if a was previously [10] and b was previously [20], you'll have this result:
>>> a, b
[10, [1,2,3]], [20,[4,5,6]]
Nah, that wasn't difficult, was it?
By the way, you probably want to merge the lists. For this, you can use extend:
list1.extend(a)
Hope it helps!
A one line solution isn't possible (unless you use some cryptic hack, which is always a bad idea).
The best you can get is:
>>> list1 = []
>>> list2 = []
>>> def func():
... return [1, 2, 3], [4, 5, 6]
...
>>> a,b = func() # Get the return values
>>> list1.append(a) # Append the first
>>> list2.append(b) # Append the second
>>> list1
[[1, 2, 3]]
>>> list2
[[4, 5, 6]]
>>>
It's readable and efficient.

How to pass one argument from list and another argument in the built-in function map() in Python?

In Python, one could apply a function foo() to every element of a list by using the built-in function map() as follows:
def foo(x):
return x*x
print map(foo, [1, 2, 3, 4])
This would print as one could guess: 1 4 9 16.
Lets say the function foo() now accepts two arguments instead of one, and is defined as follows:
def foo(x, y):
return x+y
In this case, x is an element of the list, and y is some number which is the same for the whole list. How can we use map() in this case such that foo() is applied on every element of the list, while taking another argument y which is the same for every element?
I would like to be able to do something like:
print map(foo(:, 5), [1, 2, 3, 4])
which should give me: 6 7 8 9.
Is it possible in Python? There could be alternatives for this particular example of adding 'y' to all the elements. But I am looking for an answer that would use map().
You can use a lambda function. This is treated just like a normal function, with the x value being the parameter for your iterator, and the return value being x+5 in this case.
>>> def foo(x, y)
... return x + y
...
>>> l = [1, 2, 3, 4]
>>> map(lambda x: foo(x, 5), l)
[6, 7, 8, 9]
For the record, #PaoloMoretti had this in before me :)
One way to do this is with functools.partial:
>>> from functools import partial
>>> def foo(x, y):
... return x + y
...
>>> l = [1, 2, 3, 4]
>>> map(partial(foo, y=2), l)
[3, 4, 5, 6]
>>>
Another way is to change the way you define the function:
>>> def foo(y):
... def inner(x):
... return x + y
... return inner
...
>>> map(foo(2), l)
[3, 4, 5, 6]
>>>
Incidentally, using lambda would be the most straightforward way to do this, as Paolo Moretti said. Any particular reason why you have to use map() the way you described?

How To Merge an Arbitrary Number of Tuples in Python?

I have a list of tuples:
l=[(1,2,3),(4,5,6)]
The list can be of arbitrary length, as can the tuples. I'd like to convert this into a list or tuple of the elements, in the order they appear:
f=[1,2,3,4,5,6] # or (1,2,3,4,5,6)
If I know the at development time how many tuples I'll get back, I could just add them:
m = l[0] + l[1] # (1,2,3,4,5,6)
But since I don't know until runtime how many tuples I'll have, I can't do that. I feel like there's a way to use map to do this, but I can't figure it out. I can iterate over the tuples and add them to an accumulator, but that would create lots of intermediate tuples that would never be used. I could also iterate over the tuples, then the elements of the tuples, and append them to a list. This seems very inefficient. Maybe there's an even easier way that I'm totally glossing over. Any thoughts?
Chain them (only creates a generator instead of reserving extra memory):
>>> from itertools import chain
>>> l = [(1,2,3),(4,5,6)]
>>> list(chain.from_iterable(l))
[1, 2, 3, 4, 5, 6]
l = [(1, 2), (3, 4), (5, 6)]
print sum(l, ()) # (1, 2, 3, 4, 5, 6)
reduce(tuple.__add__, [(1,2,3),(4,5,6)])
tuple(i for x in l for i in x) # (1, 2, 3, 4, 5, 6)
Use the pythonic generator style for all of the following:
b=[(1,2,3),(4,5,6)]
list = [ x for x in i for i in b ] #produces a list
gen = ( x for x in i for i in b ) #produces a generator
tup = tuple( x for x in i for i in b ) #produces a tuple
print list
>> [1, 2, 3, 4, 5, 6]
>>> from itertools import chain
>>> l = [(1,2,3),(4,5,6)]
>>> list(chain(*l))
[1, 2, 3, 4, 5, 6]
You can combine the values in a list using the .extend() function like this:
l = [(1,2,3), (4,5,6)]
m = []
for t in l:
m.extend(t)
or a shorter version using reduce:
l = [(1,2,3), (4,5,6)]
m = reduce(lambda x,y: x+list(y), l, [])

Python Add Elements of a List (or Set, or whatever Data Type is appropriate)

Is there an easy way to add the members of two equally sized lists (or tuple or whatever data type would work best)?
I have, for example a and b with 2 elements:
a = (0, 10)
b = (0, -10)
I want to add them and get as result:
result = (0, 0)
NOT (0, 10, 0, -10)
You can do this in one line in Python:
map(sum, zip(A, B))
Example:
>>> B = [1, 2, 3, 4]
>>> C = [1, 2, 4, 8]
>>> map(sum, zip(B, C))
[2, 4, 7, 12]
Three options:
>>> [a+b for (a,b) in zip(A,B)]
>>> map(int.__add__, A, B)
>>> map(sum, zip(A,B))
if you want to operate with list of numbers use numpy
>>> a = [1,2]
>>> b = [1,2]
>>> import numpy as np
>>> np.add(a,b)
array([2, 4])
>>>
You can use numpy to add the lists:
add(array([-1.2, 1.2]), array([1,3]))
and the result it:
array([-0.2, 4.2])
List ANSWER = ()
for index in range(0, len(A))
ANSWER.append(A[index]+B[index])
yes, just do this
map(sum,zip(A,B)
or, (actually clearly faster)
u=map(lambda a,b:a+b,A,B)
Timing examples:
A=range(3000)
B=range(3000)
for i in range(15000):
u=map(lambda a,b:a+b,A,B) # takes about 7.2 seconds
# u=map(sum,zip(A,B)) # takes about 11 seconds
# u=map(int.__add__,A,B) # (Edward Loper) actually also consistently ~0.5 sec slower than lambda

Categories