473,396 Members | 1,917 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Is there a list comprehension for this?


Given:
dw = [ 1, -1.1, +1.2 ]

Suppose I want to create a list 'w' that is defined as

w[0] = dw[0],
w[1] = w[0] + dw[1],
w[2] = w[1] + dw[2]

Is there a list comprehension or map expression to do it in one or 2
lines.

Nov 21 '06 #1
10 1041
dw = [ 1, -1.1, +1.2 ]
>
Suppose I want to create a list 'w' that is defined as

w[0] = dw[0],
w[1] = w[0] + dw[1],
w[2] = w[1] + dw[2]

Is there a list comprehension or map expression to do it in one or 2
lines.
Well, while it's not terribly efficient, you can do something like

w = [sum(dw[:i]) for i in xrange(1,len(dw)+1)]

Or, if you need the efficiencies for larger len(dw) values, you
could do something like
>>def f(x):
.... i = 0
.... for item in x:
.... i += item
.... yield i
....
>>list(i for i in f(dw))
[1, -0.10000000000000009, 1.0999999999999999]

Just a few ideas,

-tkc

Nov 21 '06 #2
liam_herron wrote:
Given:
dw = [ 1, -1.1, +1.2 ]

Suppose I want to create a list 'w' that is defined as

w[0] = dw[0],
w[1] = w[0] + dw[1],
w[2] = w[1] + dw[2]

Is there a list comprehension or map expression to do it in one or 2
lines.

Is this a function where you just want to know a w[n]?

then:

def w(n):
return sum((1 + i * 0.1) * (i % 2 and 1 or -1) for i in xrange(n))
otherwise:

n, w, x = 3, [], 0

for y in ((1 + i * 0.1) * (i % 2 and 1 or -1) for i in xrange(n)):
x += y
w.append(x)
Nov 21 '06 #3
liam_herron wrote:
Given:
dw = [ 1, -1.1, +1.2 ]

Suppose I want to create a list 'w' that is defined as

w[0] = dw[0],
w[1] = w[0] + dw[1],
w[2] = w[1] + dw[2]

Is there a list comprehension or map expression to do it in one or 2
lines.
One way is to use numpy (numpy.scipy.org):
In [40]: from numpy import cumsum

In [41]: dw = [1, -1.1, +1.2]

In [42]: cumsum(dw)
Out[42]: array([ 1. , -0.1, 1.1])
If you're doing a lot of numerical computing, you'll probably want a number of
other things that numpy provides.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Nov 21 '06 #4
On Tue, 21 Nov 2006 13:19:04 -0800, liam_herron wrote:
>
Given:
dw = [ 1, -1.1, +1.2 ]

Suppose I want to create a list 'w' that is defined as

w[0] = dw[0],
w[1] = w[0] + dw[1],
w[2] = w[1] + dw[2]

Is there a list comprehension or map expression to do it in one or 2
lines.
This isn't a list comp and it doesn't need map, but if you
absolutely have to have a one-liner:

w = [dw[0], dw[0] + dw[1], dw[0] + dw[1] + dw[2]]

Obviously that doesn't scale at all to larger lists, but it gives you a
better idea: replace the manual additions with sum().

w = [sum(dw[0:i]) for i in range(1, len(dw))]

but if your dw list is huge, you're spending a lot of time slicing
dw and adding up the same numbers over and over again. (This doesn't
matter if dw is small, but could become expensive if dw is huge.)

Which leads to the next version:

def running_sum(dw):
"""Return a list of the running sums of sequence dw"""
rs = [0]*len(dw)
for i in range(len(dw)):
rs[i] = dw[i] + rs[i-1]
return rs

It isn't a one-liner, but it is clear, the name is self-documenting, it
has a doc-string, you don't have to copy-and-paste code every time you
want to use it, and now that you've defined it once, you can use it as a
one-liner as many times as you like.
>>running_sum(range(5)):
[0, 1, 3, 6, 10]

--
Steven D'Aprano

Nov 22 '06 #5
Steven D'Aprano wrote:

[snip]
def running_sum(dw):
"""Return a list of the running sums of sequence dw"""
rs = [0]*len(dw)
for i in range(len(dw)):
rs[i] = dw[i] + rs[i-1]
Please explain to the newbies why there is no exception raised when
rs[i-1] is executed for i == 0, and state whether you consider this is
a Good Idea or a Filthy Trick or a Fortunate Accident.
return rs

It isn't a one-liner, but it is clear, the name is self-documenting, it
has a doc-string, you don't have to copy-and-paste code every time you
want to use it, and now that you've defined it once, you can use it as a
one-liner as many times as you like.
>running_sum(range(5)):
[0, 1, 3, 6, 10]
Nov 22 '06 #6
liam_herron wrote:
>
Given:
dw = [ 1, -1.1, +1.2 ]

Suppose I want to create a list 'w' that is defined as

w[0] = dw[0],
w[1] = w[0] + dw[1],
w[2] = w[1] + dw[2]

Is there a list comprehension or map expression to do it in one or 2
lines.
>>from itertools import *
data = [1, -1.1, 1.2]
N = 2
[sum(item) for item in izip(*[chain(repeat(0, i), di) for i, di in
enumerate(tee(data, N))])]
[1, -0.10000000000000009, 0.099999999999999867]

Should work for other values of N, too. No, I'm not serious about it...

Peter
Nov 22 '06 #7
On Tue, 21 Nov 2006 21:00:02 -0800, John Machin wrote:
Steven D'Aprano wrote:

[snip]
>def running_sum(dw):
"""Return a list of the running sums of sequence dw"""
rs = [0]*len(dw)
for i in range(len(dw)):
rs[i] = dw[i] + rs[i-1]

Please explain to the newbies why there is no exception raised when
rs[i-1] is executed for i == 0, and state whether you consider this is
a Good Idea or a Filthy Trick or a Fortunate Accident.
Because rs[0-1] is just rs[-1], which fetches the LAST item of the list. I
cunningly initialised the list to all zeroes, so adding zero to the first
term doesn't change the result value.

It is a variation of the sentinel technique, where you add an extra value
to the beginning or end of a list so that you don't need to treat the
first or last item differently. In this specific case, I think it is a
combination of Good Idea and Fortunate Accident, but since the
meaning of list[-1] is both deliberate and well-documented, it is
certainly not a Filthy Trick.
--
Steven.

Nov 22 '06 #8

Steven D'Aprano wrote:
On Tue, 21 Nov 2006 21:00:02 -0800, John Machin wrote:
Steven D'Aprano wrote:

[snip]
def running_sum(dw):
"""Return a list of the running sums of sequence dw"""
rs = [0]*len(dw)
for i in range(len(dw)):
rs[i] = dw[i] + rs[i-1]
Please explain to the newbies why there is no exception raised when
rs[i-1] is executed for i == 0, and state whether you consider this is
a Good Idea or a Filthy Trick or a Fortunate Accident.

Because rs[0-1] is just rs[-1], which fetches the LAST item of the list. I
cunningly initialised the list to all zeroes, so adding zero to the first
term doesn't change the result value.

It is a variation of the sentinel technique, where you add an extra value
to the beginning or end of a list so that you don't need to treat the
first or last item differently. In this specific case, I think it is a
combination of Good Idea and Fortunate Accident, but since the
meaning of list[-1] is both deliberate and well-documented, it is
certainly not a Filthy Trick.
Fair enough. But it does make the concerned reader go back a couple of
lines to see why it doesn't run amok. Here's my attempt at a
no-reader-backtracking solution:

def running_sum_2(dw):
rs = dw[:1]
for i in xrange(1, len(dw)):
rs.append(dw[i] + rs[-1])
return rs

Comments invited.

Cheers,
John

Nov 22 '06 #9
On Wed, 22 Nov 2006 02:28:04 -0800, John Machin wrote:
>
Steven D'Aprano wrote:
>On Tue, 21 Nov 2006 21:00:02 -0800, John Machin wrote:
Steven D'Aprano wrote:

[snip]

def running_sum(dw):
"""Return a list of the running sums of sequence dw"""
rs = [0]*len(dw)
for i in range(len(dw)):
rs[i] = dw[i] + rs[i-1]

Please explain to the newbies why there is no exception raised when
rs[i-1] is executed for i == 0, and state whether you consider this is
a Good Idea or a Filthy Trick or a Fortunate Accident.

Because rs[0-1] is just rs[-1], which fetches the LAST item of the list. I
cunningly initialised the list to all zeroes, so adding zero to the first
term doesn't change the result value.

It is a variation of the sentinel technique, where you add an extra value
to the beginning or end of a list so that you don't need to treat the
first or last item differently. In this specific case, I think it is a
combination of Good Idea and Fortunate Accident, but since the
meaning of list[-1] is both deliberate and well-documented, it is
certainly not a Filthy Trick.

Fair enough. But it does make the concerned reader go back a couple of
lines to see why it doesn't run amok.
Nobody said that every piece of code should be instantly comprehensible
just at a glance. Sometimes you do actually have to think about code to
understand it, even in Python :)
Here's my attempt at a
no-reader-backtracking solution:

def running_sum_2(dw):
rs = dw[:1]
for i in xrange(1, len(dw)):
rs.append(dw[i] + rs[-1])
return rs

Comments invited.
Even with xrange() instead of range, it is a little slower than my version
for largish input lists because you are repeatedly appending to a list.
>>timeit.Timer("running_sum(L)",
.... "from __main__ import running_sum; L = range(500)").timeit(1000)
0.56354999542236328
>>timeit.Timer("running_sum_2(L)",
.... "from __main__ import running_sum_2; L = range(500)").timeit(1000)
0.68534302711486816

Although the speed difference disappears (or even reverses) for small
enough lists. Either way, it isn't really a major speed difference --
Python's resizing of lists is very smart.

But why build a list of all the running sums when you probably only need
them one at a time? Here's a generator version that can take any iterable,
not just a sequence:

def running_sum_3(iterable):
sum_ = 0
for x in iterable:
sum_ += x
yield sum_

And it is considerably faster than either of the list-only versions:
>>timeit.Timer("list(running_sum_3(L))",
.... "from __main__ import running_sum_3; L = range(500)").timeit(1000)
0.33915305137634277

--
Steve.

Nov 22 '06 #10
Steven D'Aprano wrote:
On Wed, 22 Nov 2006 02:28:04 -0800, John Machin wrote:

Steven D'Aprano wrote:
On Tue, 21 Nov 2006 21:00:02 -0800, John Machin wrote:

Steven D'Aprano wrote:

[snip]

def running_sum(dw):
"""Return a list of the running sums of sequence dw"""
rs = [0]*len(dw)
for i in range(len(dw)):
rs[i] = dw[i] + rs[i-1]

Please explain to the newbies why there is no exception raised when
rs[i-1] is executed for i == 0, and state whether you consider this is
a Good Idea or a Filthy Trick or a Fortunate Accident.

Because rs[0-1] is just rs[-1], which fetches the LAST item of the list. I
cunningly initialised the list to all zeroes, so adding zero to the first
term doesn't change the result value.

It is a variation of the sentinel technique, where you add an extra value
to the beginning or end of a list so that you don't need to treat the
first or last item differently. In this specific case, I think it is a
combination of Good Idea and Fortunate Accident, but since the
meaning of list[-1] is both deliberate and well-documented, it is
certainly not a Filthy Trick.
Fair enough. But it does make the concerned reader go back a couple of
lines to see why it doesn't run amok.

Nobody said that every piece of code should be instantly comprehensible
just at a glance.
That's correct. I didn't say it, and nobody else did. You argue ad
extremis, in extremis :-)

My point was merely that it is preferable to be able to understand code
without having to go "OMG!" and then read backwards ...
Sometimes you do actually have to think about code to
understand it, even in Python :)
Correct. However I raised the question explicitly in the context of an
answer to a *newbie* ("Please explain to the newbies").
Notwithstandingly, you then mentioned "cunningly" and
"[well-]documented" and now "think" :-)
>
Here's my attempt at a
no-reader-backtracking solution:

def running_sum_2(dw):
rs = dw[:1]
for i in xrange(1, len(dw)):
rs.append(dw[i] + rs[-1])
return rs

Comments invited.
[snip]
>
Although the speed difference disappears (or even reverses) for small
enough lists. Either way, it isn't really a major speed difference --
As you say. Perhaps I should have stated in advance how many goalposts
and whether they had a cross-bar or not :-) I was hoping for comments
on the understandibility or otherwise of rs[-1]. My use of xrange was
out of habit; it wasn't intended to provoke the cannonball run.
>
But why build a list of all the running sums when you probably only need
them one at a time? Here's a generator version that can take any iterable,
not just a sequence:
.... and whether the cross-bar had a net slung from it :-)

Why? (1) Because that's what the OP was asking for IIRC. (2) Because
some applications (at least back when the storage mechanism was squared
paper) involved cumulative sums of cumulative sums of ... generator
version, please :-)

N.B. This is even more fun than discussing cricket with my Pommie
neighbour; keep it up :-)

Best regards,
John

Nov 22 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: jsaul | last post by:
Hi there, wouldn't it be useful to have a 'while' conditional in addition to 'if' in list comprehensions? foo = for i in bar: if len(i) == 0: break foo.append(i)
23
by: Fuzzyman | last post by:
Pythons internal 'pointers' system is certainly causing me a few headaches..... When I want to copy the contents of a variable I find it impossible to know whether I've copied the contents *or*...
35
by: Moosebumps | last post by:
Does anyone here find the list comprehension syntax awkward? I like it because it is an expression rather than a series of statements, but it is a little harder to maintain it seems. e.g. you...
7
by: Chris P. | last post by:
Hi. I've made a program that logs onto a telnet server, enters a command, and then creates a list of useful information out of the information that is dumped to the screen as a result of the...
6
by: jena | last post by:
hello, when i create list of lambdas: l=] then l() returns 'C', i think, it should be 'A' my workaround is to define helper class with __call__ method: class X: def __init__(self,s): self.s=s...
18
by: a | last post by:
can someone tell me how to use them thanks
4
by: Gregory Guthrie | last post by:
Sorry for a simple question- but I don't understand how to parse this use of a list comprehension. The "or" clauses are odd to me. It also seems like it is being overly clever (?) in using a...
4
by: bullockbefriending bard | last post by:
Given: class Z(object): various defs, etc. class ZList(list): various defs, etc. i would like to be able to replace
4
by: beginner | last post by:
Hi All, If I have a list comprehension: ab= c = "ABC" print c
1
by: Ken Pu | last post by:
Hi all, I observed an interesting yet unpleasant variable scope behaviour with list comprehension in the following code: print print x It outputs:
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.