Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #50059 > unrolled thread
| Started by | Russel Walker <russ.pobox@gmail.com> |
|---|---|
| First post | 2013-07-06 05:37 -0700 |
| Last post | 2013-07-07 09:44 -0700 |
| Articles | 11 — 6 participants |
Back to article view | Back to comp.lang.python
Simple recursive sum function | what's the cause of the weird behaviour? Russel Walker <russ.pobox@gmail.com> - 2013-07-06 05:37 -0700
Re: Simple recursive sum function | what's the cause of the weird behaviour? Russel Walker <russ.pobox@gmail.com> - 2013-07-06 05:54 -0700
Re: Simple recursive sum function | what's the cause of the weird behaviour? Russel Walker <russ.pobox@gmail.com> - 2013-07-06 05:59 -0700
Re: Simple recursive sum function | what's the cause of the weird behaviour? Peter Otten <__peter__@web.de> - 2013-07-06 15:19 +0200
Re: Simple recursive sum function | what's the cause of the weird behaviour? Joshua Landau <joshua.landau.ws@gmail.com> - 2013-07-06 19:43 +0100
Re: Simple recursive sum function | what's the cause of the weird behaviour? Rotwang <sg552@hotmail.co.uk> - 2013-07-06 21:10 +0100
Re: Simple recursive sum function | what's the cause of the weird behaviour? Rotwang <sg552@hotmail.co.uk> - 2013-07-06 21:25 +0100
Re: Simple recursive sum function | what's the cause of the weird behaviour? Chris Angelico <rosuav@gmail.com> - 2013-07-07 03:22 +1000
Re: Simple recursive sum function | what's the cause of the weird behaviour? Terry Reedy <tjreedy@udel.edu> - 2013-07-06 14:47 -0400
Re: Simple recursive sum function | what's the cause of the weird behaviour? Russel Walker <russ.pobox@gmail.com> - 2013-07-07 09:13 -0700
Re: Simple recursive sum function | what's the cause of the weird behaviour? Russel Walker <russ.pobox@gmail.com> - 2013-07-07 09:44 -0700
| From | Russel Walker <russ.pobox@gmail.com> |
|---|---|
| Date | 2013-07-06 05:37 -0700 |
| Subject | Simple recursive sum function | what's the cause of the weird behaviour? |
| Message-ID | <e3ab7b0a-d6cb-454c-aa8a-80cf4e3fc569@googlegroups.com> |
I know this is simple but I've been starring at it for half an hour and trying all sorts of things in the interpreter but I just can't see where it's wrong.
def supersum(sequence, start=0):
result = start
for item in sequence:
try:
result += supersum(item, start)
except:
result += item
return result
It's supposed to work like the builtin sum, but on multidimensional lists and also with the optional start parameter accepting something like an empty list and so would also works as a robust list flattener. It's just for kicks, I'm not actually going to use it for anything.
This works:
- - - - - -
>>> x = [[1], [2], [3]]
>>> supersum(x)
6
>>> supersum(x, [])
[1, 2, 3]
>>>
This does not:
- - - - - - -
>>> x = [[[1], [2]], [3]]
>>> supersum(x, [])
[1, 2, 1, 2, 3]
>>>
[toc] | [next] | [standalone]
| From | Russel Walker <russ.pobox@gmail.com> |
|---|---|
| Date | 2013-07-06 05:54 -0700 |
| Message-ID | <e0cea5d3-6eaf-441f-b255-4f17e4b13521@googlegroups.com> |
| In reply to | #50059 |
Nevermind! Stupid of me to forget that lists or mutable so result and start both point to the same list.
[toc] | [prev] | [next] | [standalone]
| From | Russel Walker <russ.pobox@gmail.com> |
|---|---|
| Date | 2013-07-06 05:59 -0700 |
| Message-ID | <a1f94b4e-415b-4d5d-b1d5-9991c3890287@googlegroups.com> |
| In reply to | #50059 |
Since I've already wasted a thread I might as well...
Does this serve as an acceptable solution?
def supersum(sequence, start=0):
result = type(start)()
for item in sequence:
try:
result += supersum(item, start)
except:
result += item
return result
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-07-06 15:19 +0200 |
| Message-ID | <mailman.4335.1373116733.3114.python-list@python.org> |
| In reply to | #50061 |
Russel Walker wrote: > Since I've already wasted a thread I might as well... > > Does this serve as an acceptable solution? > > def supersum(sequence, start=0): > result = type(start)() > for item in sequence: > try: > result += supersum(item, start) > except: > result += item > return result That depends on what is an acceptable result ;) For instance: >>> supersum([2, 3], 1) 5 >>> supersum([[1], ["abc"]], []) [1, 'a', 'b', 'c']
[toc] | [prev] | [next] | [standalone]
| From | Joshua Landau <joshua.landau.ws@gmail.com> |
|---|---|
| Date | 2013-07-06 19:43 +0100 |
| Message-ID | <mailman.4341.1373136270.3114.python-list@python.org> |
| In reply to | #50061 |
On 6 July 2013 13:59, Russel Walker <russ.pobox@gmail.com> wrote:
> Since I've already wasted a thread I might as well...
>
> Does this serve as an acceptable solution?
>
> def supersum(sequence, start=0):
> result = type(start)()
> for item in sequence:
> try:
> result += supersum(item, start)
> except:
> result += item
> return result
It's probably more robust to do:
def supersum(sequence, start=0):
for item in sequence:
try:
result = result + supersum(item, start)
except:
result = result + item
return result
as that way you aren't assuming the signature of type(start).
[toc] | [prev] | [next] | [standalone]
| From | Rotwang <sg552@hotmail.co.uk> |
|---|---|
| Date | 2013-07-06 21:10 +0100 |
| Message-ID | <kr9t9m$f1p$1@dont-email.me> |
| In reply to | #50073 |
On 06/07/2013 19:43, Joshua Landau wrote:
> On 6 July 2013 13:59, Russel Walker <russ.pobox@gmail.com> wrote:
>> Since I've already wasted a thread I might as well...
>>
>> Does this serve as an acceptable solution?
>>
>> def supersum(sequence, start=0):
>> result = type(start)()
>> for item in sequence:
>> try:
>> result += supersum(item, start)
>> except:
>> result += item
>> return result
>
> It's probably more robust to do:
>
> def supersum(sequence, start=0):
> for item in sequence:
> try:
> result = result + supersum(item, start)
> except:
> result = result + item
> return result
I assume you meant to put "result = start" in there at the beginning.
> as that way you aren't assuming the signature of type(start).
It's not quite clear to me what the OP's intentions are in the general
case, but calling supersum(item, start) seems odd - for example, is the
following desirable?
>>> supersum([[1], [2], [3]], 4)
22
I would have thought that the "correct" answer would be 10. How about
the following?
def supersum(sequence, start = 0):
result = start
for item in reversed(sequence):
try:
result = supersum(item, result)
except:
result = item + result
return result
[toc] | [prev] | [next] | [standalone]
| From | Rotwang <sg552@hotmail.co.uk> |
|---|---|
| Date | 2013-07-06 21:25 +0100 |
| Message-ID | <kr9u5s$h29$1@dont-email.me> |
| In reply to | #50080 |
On 06/07/2013 21:10, Rotwang wrote:
> [...]
>
> It's not quite clear to me what the OP's intentions are in the general
> case, but calling supersum(item, start) seems odd - for example, is the
> following desirable?
>
> >>> supersum([[1], [2], [3]], 4)
> 22
>
> I would have thought that the "correct" answer would be 10. How about
> the following?
>
> def supersum(sequence, start = 0):
> result = start
> for item in reversed(sequence):
> try:
> result = supersum(item, result)
> except:
> result = item + result
> return result
Sorry, I've no idea what I was thinking with that reversed thing. The
following seems better:
def supersum(sequence, start = 0):
result = start
for item in sequence:
try:
result = supersum(item, result)
except:
result = result + item
return result
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-07-07 03:22 +1000 |
| Message-ID | <mailman.4340.1373131363.3114.python-list@python.org> |
| In reply to | #50059 |
On Sat, Jul 6, 2013 at 10:37 PM, Russel Walker <russ.pobox@gmail.com> wrote: > This works: > - - - - - - >>>> x = [[1], [2], [3]] >>>> supersum(x) > 6 >>>> supersum(x, []) > [1, 2, 3] >>>> > > > This does not: > - - - - - - - >>>> x = [[[1], [2]], [3]] >>>> supersum(x, []) > [1, 2, 1, 2, 3] >>>> You have a problem of specification here. What should supersum do with the list [1]? Should it recurse into it, or append it as a list? It can't do both. For a list flattener, you would need to either use .append for each element you come across, or .extend with each list, with some kind of check to find whether you should recurse or not. Still, it's a fun thing to play with. I like code golfing these sorts of trinketty functions, just for fun :) ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2013-07-06 14:47 -0400 |
| Message-ID | <mailman.4342.1373136464.3114.python-list@python.org> |
| In reply to | #50059 |
On 7/6/2013 8:37 AM, Russel Walker wrote: > I know this is simple but I've been starring at it for half an hour and trying all sorts of things in the interpreter but I just can't see where it's wrong. > > def supersum(sequence, start=0): > result = start > for item in sequence: > try: > result += supersum(item, start) > except: Bare except statements cover up too many sins. I and others *strongly* recommend that you only catch what you *know* you actually want to (see below). > result += item > return result I recommend that you start with at least one test case, and with an edge case at that. If you cannot bring yourself to do it before writing a draft of the function code, do it immediately after and run. If you do not want to use a framework, use assert. assert supersum([]) == 0 assert supersum([], []) == [] Do the asserts match your intention? The tests amount to a specification by example. Any 'kind' of input that is not tested is not guaranteed to work. Back to the except clause: only add try..except xxx when needed to pass a test. -- Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Russel Walker <russ.pobox@gmail.com> |
|---|---|
| Date | 2013-07-07 09:13 -0700 |
| Message-ID | <b50b60a5-aef0-4a8b-b9bb-7901bb10e633@googlegroups.com> |
| In reply to | #50059 |
I read through all of the posts and thanks for helping. What was supposed to be simple a (recursively) straightforward, turned out to be quite tricky.
I've set up a small testing bench and tried all of the proposed solutions including my own but none pass. I'll post it below.
I've also discovered something about lists that explains the very first "weird" result I was observing, which I realized was because lists are mutable etc, but more specifically:
This
>>> a = [1, 2]
>>> a += [3]
is equivalent to, AFAIK, this
>>> a = [1, 2]
>>> a.extend([3])
So to overcome that you just have to do
>>> a = [1, 2]
>>> a = a + [3]
Which creates a new list. So any variables which were pointing to the same list as a, are unaffected.
Summary
- - - -
>>> # --- Bad ---
>>> a = [1, 2]
>>> b = a
>>> a += [3]
>>> print a
[1, 2, 3]
>>> print b
[1, 2, 3]
>>> # --- Good ---
>>> a = [1, 2]
>>> b = a
>>> a = a + [3]
>>> print a
[1, 2, 3]
>>> print b
[1, 2]
And as for the testbench:
def supersum(seq, start=0):
return
# ---------------- Testing -------------------------------- >
testcases = [
# (seq, start, result)
# arithmetic sums
([], 0, 0),
([[], []], 0, 0),
([[], [[],[]]], 0, 0),
([1], 0, 1),
([[], [1]], 0, 1),
([[], [[],[1, 1]]], 0, 2),
([[1], [1]], 0, 2),
([[1], [[1],[1, 1]]], 0, 4),
([[1], [[1],[1, 1]]], 1, 5),
# list flattening
([], [], []),
([[], []], [], []),
([[], [[],[]]], [], []),
([], [1], [1]),
([[], []], [1], [1]),
([[], [[],[]]], [1], [1]),
([1], [1], [1, 1]),
([[1], [1]], [1], [1, 1]),
([[1], [[1],[1]]], [1], [1, 1, 1, 1]),
]
for seq, start, result in testcases:
try:
assert supersum(seq, start) == result
except Exception as er:
print "seq:%s\t start:%s" % (seq, start)
if type(er) is AssertionError:
print "expected:", result
print "got: ", supersum(seq, start)
else:
print repr(er)
print ''
[toc] | [prev] | [next] | [standalone]
| From | Russel Walker <russ.pobox@gmail.com> |
|---|---|
| Date | 2013-07-07 09:44 -0700 |
| Message-ID | <d449aab3-f5ab-4a86-b7fa-07ab0d977e7a@googlegroups.com> |
| In reply to | #50059 |
I got it! One of the testcases was wrong,
([[1], [1]], [1], [1, 1]),
should be
([[1], [1]], [1], [1, 1, 1]),
And the working solution.
def supersum(sequence, start=0):
result = start
start = type(start)()
for item in sequence:
try:
item = supersum(item, start)
except TypeError:
pass
try:
result = result + item
except TypeError:
return result + sequence
return result
I couldn't yet get around doing type(start)() and it's pretty messy, but anyways...
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web