I've been looking around for this but can't find what I would like to. I'm sure I've seen this done before but I can't seem to find it. Here's an example:
In this case I would like to take the difference of each element in an array,
#Generate sample list
B = [a**2 for a in range(10)]
#Take difference of each element
C = [(b+1)-b for b in B]
the (b+1) is to denote the next element in the array which I don't know how to do and obviously doesn't work, giving the result:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
the result I would like is:
[1, 3, 5, 7, 9, 11, 13, 15, 17]
I understand that this result is shorter than the original array however the reason for this would be to replace ugly expressions such as:
C = [B[i+1]-B[i] for i in range(len(B)-1)]
In this case it really isn't that bad at all, but there are cases that I need to iterate through multiple variables with long expressions and it gets annoying to keep having to write the index in each time. Right now I'm hoping that there is an easy pythonic way to do this that I don't know about...
EDIT: An example of what I mean about having to do this with multiple variables would be:
X = [a for a in range(10)]
Y = [a**2 for a in range(10)]
Z = [a**3 for a in range(10)]
for x,y,z in zip(X,Y,Z):
x + (x+1) + (y-(y+1))/(z-(z+1))
where (x+1),(y+1),(z+1) denote the next element rather than:
for i in range(len(X)):
x[i] + x[i+1] + (y[i]-y[i+1])/(z[i]-z[i+1])
I am using python 2.7.5 btw
re: your edit
zip is still the right solution. You just need to zip together two iterators over the lists, the second of which should be advanced one tick.
from itertools import izip,tee
cur,nxt = tee(izip(X,Y,Z))
next(nxt,None) #advance nxt iterator
for (x1,y1,z1),(x2,y2,z2) in izip(cur,nxt):
print x1 + x2 + (y1-y2)/(z1-z2)
If you don't like the inline next call, you can use islice like #FelixKling mentioned: izip(cur,islice(nxt, 1, None)).
Alternative you can use zip, to create tuples of the current value, next value:
C = [b - a for a, b in zip(B, B[1:])]
I believe zip returns a generator in Python 3. In Python 2, you might want to use izip. And B[1:], you could use islice: islice(B, 1, None).
Maybe you want enumerate. As follows:
C = [B[b+1]-item for b,item in enumerate(B[:-1])]
or simply:
C = [B[b+1]-B[b] for b in range(len(B[:-1]))]
They both work.
Examples
>>> B = [a**2 for a in range(10)]
>>> C = [B[b+1]-item for b,item in enumerate(B[:-1])]
>>> print C
[1, 3, 5, 7, 9, 11, 13, 15, 17]
This is a pretty weird way, but it works!
b = [a**2 for a in range(10)]
print b
print reduce(lambda x, y:len(x) and x[:-1]+[y-x[-1], y] or [y], b, [])
I have created a bunk on CodeBunk so you can run the it too
http://codebunk.com/b/-JJzLIA-KZgASR_3a-I8
Related
Is it possible to define a recursive list comprehension in Python?
Possibly a simplistic example, but something along the lines of:
nums = [1, 1, 2, 2, 3, 3, 4, 4]
willThisWork = [x for x in nums if x not in self] # self being the current comprehension
Is anything like this possible?
No, there's no (documented, solid, stable, ...;-) way to refer to "the current comprehension". You could just use a loop:
res = []
for x in nums:
if x not in res:
res.append(x)
of course this is very costly (O(N squared)), so you can optimize it with an auxiliary set (I'm assuming that keeping the order of items in res congruent to that of the items in nums, otherwise set(nums) would do you;-)...:
res = []
aux = set()
for x in nums:
if x not in aux:
res.append(x)
aux.add(x)
this is enormously faster for very long lists (O(N) instead of N squared).
Edit: in Python 2.5 or 2.6, vars()['_[1]'] might actually work in the role you want for self (for a non-nested listcomp)... which is why I qualified my statement by clarifying there's no documented, solid, stable way to access "the list being built up" -- that peculiar, undocumented "name" '_[1]' (deliberately chosen not to be a valid identifier;-) is the apex of "implementation artifacts" and any code relying on it deserves to be put out of its misery;-).
Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), which gives the possibility to name the result of an expression, we could reference items already seen by updating a variable within the list comprehension:
# items = [1, 1, 2, 2, 3, 3, 4, 4]
acc = []; [acc := acc + [x] for x in items if x not in acc]
# acc = [1, 2, 3, 4]
This:
Initializes a list acc which symbolizes the running list of elements already seen
For each item, this checks if it's already part of the acc list; and if not:
appends the item to acc (acc := acc + [x]) via an assignment expression
and at the same time uses the new value of acc as the mapped value for this item
Actually you can! This example with an explanation hopefully will illustrate how.
define recursive example to get a number only when it is 5 or more and if it isn't, increment it and call the 'check' function again. Repeat this process until it reaches 5 at which point return 5.
print [ (lambda f,v: v >= 5 and v or f(f,v+1))(lambda g,i: i >= 5 and i or g(g,i+1),i) for i in [1,2,3,4,5,6] ]
result:
[5, 5, 5, 5, 5, 6]
>>>
essentially the two anonymous functions interact in this way:
let f(g,x) = {
expression, terminal condition
g(g,x), non-terminal condition
}
let g(f,x) = {
expression, terminal condition
f(f,x), non-terminal condition
}
make g,f the 'same' function except that in one or both add a clause where the parameter is modified so as to cause the terminal condition to be reached and then go
f(g,x) in this way g becomes a copy of f making it like:
f(g,x) = {
expression, terminal condition
{
expression, terminal condition,
g(g,x), non-terminal codition
}, non-terminal condition
}
You need to do this because you can't access the the anonymous function itself upon being executed.
i.e
(lambda f,v: somehow call the function again inside itself )(_,_)
so in this example let A = the first function and B the second. We call A passing B as f and i as v. Now as B is essentially a copy of A and it's a parameter that has been passed you can now call B which is like calling A.
This generates the factorials in a list
print [ (lambda f,v: v == 0 and 1 or v*f(f,v-1))(lambda g,i: i == 0 and 1 or i*g(g,i-1),i) for i in [1,2,3,5,6,7] ]
[1, 2, 6, 120, 720, 5040]
>>>
Not sure if this is what you want, but you can write nested list comprehensions:
xs = [[i for i in range(1,10) if i % j == 0] for j in range(2,5)]
assert xs == [[2, 4, 6, 8], [3, 6, 9], [4, 8]]
From your code example, you seem to want to simply eliminate duplicates, which you can do with sets:
xs = sorted(set([1, 1, 2, 2, 3, 3, 4, 4]))
assert xs == [1, 2, 3, 4]
no. it won't work, there is no self to refer to while list comprehension is being executed.
And the main reason of course is that list comprehensions where not designed for this use.
No.
But it looks like you are trying to make a list of the unique elements in nums.
You could use a set:
unique_items = set(nums)
Note that items in nums need to be hashable.
You can also do the following. Which is a close as I can get to your original idea. But this is not as efficient as creating a set.
unique_items = []
for i in nums:
if i not in unique_items:
unique_items.append(i)
Do this:
nums = [1, 1, 2, 2, 3, 3, 4, 4]
set_of_nums = set(nums)
unique_num_list = list(set_of_nums)
or even this:
unique_num_list = sorted(set_of_nums)
I need to perform a calculation on a list using both the values of that list, and the index of those values, eg:
a = [1,2,3,4,5]
b= a[1]*1
but for all values of a, to get:
b = [1,4,9,16,25]
Is this possible to do without a for loop? I could put it in one, but it would change the structure of my code for the worse. This is meant to be used by a wide variety of users with varying skill levels, so I'm willing to sacrifice speed for ease of readability.
You can use list comprehension and enumerate() function, that provides the index as well as value of the element, simultaneously. Example -
b = [elem * (i+1) for i, elem in enumerate(a)]
Demo -
>>> a = [1,2,3,4,5]
>>> b = [elem * (i+1) for i, elem in enumerate(a)]
>>> b
[1, 4, 9, 16, 25]
If its fine to use numpy library , most probably a faster solution would be to use numpy's vectorised multiplication . Example -
In [1]: import numpy as np
In [2]: a = [1,2,3,4,5]
In [3]: a_arr = np.array(a)
In [4]: b = a_arr * np.arange(1,a_arr.shape[0]+1)
In [5]: b
Out[5]: array([ 1, 4, 9, 16, 25])
Though numpy method may be a bit more complex to understand that the list comprehension.
I recommend you to use map built-in function and let your code be simpler.
a = [1,2,3,4,5]
b = map(lambda x: x*x, a)
print b
# [1, 4, 9, 16, 25]
If you want to dynamically enter your list, you would use range built-in function (It's available for python2):
b = map(lambda x: x*x, range(1,6))
print b
# [1, 4, 9, 16, 25]
I have a spectra of wavelengths as a list and some number of other lists I use in a formula (using tmm.tmm_core). Is there something more efficient than iterating through the wavelength if I'm just basically doing the same thing for all wavelengths?
Example
def go(n, thk, theta):
#do stuff
return(something)
wv = [1, 2, 3, 4]
a_vec = [3, 7, 3, 9]
b_vec = [6, 5, 9, 3]
c_vec = [0, 1, 8, 9]
theta = 0
th = [10, 1, 10]
final = []
for i in range(len(wv)):
n = [a[i], b[i], c[i]]
answer = go(n, th, theta)
final.append(answer)
in reality there are maybe 5000-10000 rows. It just seems to lag a bit when I press go and I assume it's because of the iteration. Pretty new to optimizing so I haven't used any benchmarking tools or anything.
I think you're looking for the map function in Python!
>>> list1 = [1,2,3,4]
>>> list2 = [5,6,7,8]
>>> map(lambda x,y: x+y, list1, list2)
[6, 8, 10, 12]
it takes in a function (in the above case, an anonymous lambda function), one or more lists and returns another list. At each iteration within the function, both lists are iterated and the result is added to the new list. You don't need to limit yourself to the expressive power of a lambda statement; you can also use globally defined functions as in the case below:
>>> def go(a,b,c):
... return a+b+c
...
>>> map(go, list1,list2, range(9,13))
[15, 18, 21, 24]
You can put all of your lists within a custom list like C_list and use map to create a new list all_len contain the length of all lists then use a list comprehension to create the list final :
all_len=map(len,C_list)
final =[[go([a[i], b[i], c[i]], th, theta) for i in range(li)] for li in all_len]
Also if the length of a and b and c are equal you can use zip function to zip then and refuse of multiple indexing :
all_len=map(len,C_list)
z=zip(a,b,c)
final =[[go(z[i], th, theta) for i in range(li)] for li in all_len]
If you have to perform an operation on every item in the list, then you're gonna have to go through every item in the list. However, you could gain speed through the use of list comprehensions: List Comprehensions
Here are several list: a, b, etc
I want to make some change of them respectively, but I'm confused with the behavier of for loop.
for example:
if we do
a, b = range(5), range(5,10)
for x in [a, b]: x += [0]
print(a,b)
we get
([0, 1, 2, 3, 4, 0], [5, 6, 7, 8, 9, 0])
a,b are modified.
but if we do
a, b = range(5), range(5,10)
for x in [a, b]: x = x + [0]
print(a,b)
we get
([0, 1, 2, 3, 4], [5, 6, 7, 8, 9])
a,b aren't modified.
I'm confused, what's the relation between x and a? When or how I can modify the value of a with x?
And by the way, what's the difference between a+=b and a=a+b?
Anyway, I find a solution that we can do like this
a, b = range(5), range(5,10)
lis = [a, b]
for i, x in enumerate(lis):
lis[i] = ...
then we can modify values of a & b. But this method need make a extra list.
And there's anther solution
for x in ['a', 'b']:
exec(x + '=' + x + '+ ...')
And an easier solution
a, b = range(5), range(5,10)
for x in [a, b]: x[:] = x + [0]
print(a,b)
We will find a,b are modified :)
The relation is the same as with all variable binding in Python. The name is bound to the value. The differences you are seeing are because you are doing different things, sometimes, operating on the value and sometimes on the name.
For lists, += extends the list in-place --- that is, it modifies the original list. Thus the modifications are visible everywhere that list is used.
When you do x = x + [0], you rebind the name x to a new list (formed by adding the old list plus [0]). This does not modify the original list, so other places that use that list will not see the change.
If you search around for Python questions on "variables", "names", "values", "call by refernce" and the like you will find other discussions of this. Here is a question discussing a similar issue in the context of function-parameter binding. The principles are the same in for-loop variable binding.
The line:
x += something
changes a list in place, while:
x = x + something
creates a brand new list by joining x and something.
It's no different to the following simplified demonstration:
>>> a = [7] # The object is [7], name a is connected to it.
>>> x = a # Now name x is also connected.
>>> x += [2] # Here we change the backing object (behind a AND x).
>>> a # So that both names seem to change.
[7, 2]
>>> x
[7, 2]
>>> a = [7] # The object is [7], name a is connected to it.
>>> x = a # Now name x is also connected.
>>> x = x + [2] # Here we create a NEW object from the old one, and connect x.
>>> a # So a is unchanged.
[7]
>>> x # But x IS changed.
[7, 2]
This was the hardest thing I had to get used to in Python, the fact that names and the objects that names refer to are quite disparate, and can often act in surprising ways. It's also one of its most beautiful features once you nut it out.
I eventually just started thinking that names were C pointers and all objects were on the heap (since that was where I have my expertise). There may be better ways to think of it, though I've never found any for me.
I have two lists:
A = [1, 2, 3, 4, 5]
B = [6, 7, 8, 9, 10]
And I need to be able to find the sum of the nth terms from both lists i.e. 1+6, 2+7, 3+8 etc
Could someone please tell me how to refer to items in both lists at the same time?
I read somewhere that I could do Sum = a[i] + b[i] but I'm not convinced on how that would work.
>>> import operator
>>> map(operator.add, A, B)
[7, 9, 11, 13, 15]
just to demonstrate Pythons elegance :-)
Use a list comprehension and zip:
[a + b for (a,b) in zip(A,B)]
Are these questions homework? Or self-study?
If you know the lists will be the same length, you could do this:
AB = [A[i] + B[i] for i in range(len(A))]
In Python 2, you might want to use xrange instead of range if your lists are quite large. I think that's an explicit, simple, readable, obvious way to do it, but some might differ.
If the lists might be different lengths, you have to decide how you want to handle the extra elements. Let's say you want to ignore the extra elements of whichever list is longer. Here are three ways to do it:
AB = [A[i] + B[i] for i in range(min(len(A), len(B)))]
AB = map(sum, zip(A, B))
AB = [a + b for a, b in zip(A, B)]
The downside of using zip is that it will allocate a list of tuples, which can be a lot of memory if your lists are already large. Using for i in xrange with subscripting won't allocate all that memory, or you can use itertools.izip:
import itertools
AB = map(sum, itertools.izip(A, B))
If you instead want to pretend the shorter list is padded with zeros, using itertools.izip_longest is the shortest answer:
import itertools
AB = map(sum, itertools.izip_longest(A, B, fillvalue=0))
or
import itertools
AB = [a + b for a, b in itertools.izip_longest(A, B, fillvalue=0)]
Although Jazz's solution works for 2 lists, what if you have more than 2 lists? Here's a solution:
def apply_elementwise_function(elements_in_iterables, function):
elementwise_function = lambda x, y: itertools.imap(function, itertools.izip(x, y))
return reduce(elementwise_function, elements_in_iterables)
a = b = c = [1, 2, 3]
>>> list(apply_elementwise_function([a, b, c], sum))
[3, 6, 9]
Hi You can try this too:
>>>a=[1,2,3,4,5]
>>>b=[6,7,8,9,10]
>>>c=[]
>>>for i in range(0,5):
c.append(a[i]+b[i])
>>> c
[7, 9, 11, 13, 15]