Re: Idiomatic Python for incrementing pairs

2013-06-08 Thread Steven D'Aprano
On Fri, 07 Jun 2013 21:32:39 -0500, Tim Chase wrote:

 Playing around, I've been trying to figure out the most pythonic way of
 incrementing multiple values based on the return of a function.
 Something like
[...skip misleading and irrelevant calculate() function...]

   alpha = beta = 0
   temp_a, temp_b = calculate(...)
   alpha += temp_a
   beta += temp_b
 
 Is there a better way to do this without holding each temporary result
 before using it to increment?

Not really. The above idiom is not really terribly Pythonic. It's more 
like the sort of old-fashioned procedural code I'd write in Pascal or 
COBOL or similar.

For just two variables, it's not so bad, although I'd probably save a 
line and a temporary variable and write it as this:

alpha = beta = 0
tmp = calculate(...)
alpha, beta = alpha+tmp[0], beta+tmp[1]


But if you have many such values, that's a sign that you're doing it 
wrong. Do it like this instead:

values = [0]*17  # or however many variables you have
increments = calculate(...)
values = [a+b for a,b in zip(values, increments)]


Or define a helper function:

add(v1, v2):
Vector addition.

 add([1, 2], [4, 5])
[5, 7]


return [a+b for a,b in zip(v1, v2)]


values = [0]*17
increments = calculate(...)
values = add(values, increments)


Much nicer!

And finally, if speed is absolutely critical, this scales to using fast 
vector libraries like numpy. Just use numpy arrays instead of lists, and 
+ instead of the add helper function, and Bob's yer uncle.


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Idiomatic Python for incrementing pairs

2013-06-08 Thread Peter Otten
Tim Chase wrote:

 On 2013-06-07 23:46, Jason Swails wrote:
 On Fri, Jun 7, 2013 at 10:32 PM, Tim Chase
def calculate(params):
  a = b = 0
  if some_calculation(params):
a += 1
  if other_calculation(params):
b += 1
  return (a, b)
 
alpha = beta = 0
temp_a, temp_b = calculate(...)
alpha += temp_a
beta += temp_b
 
  Is there a better way to do this without holding each temporary
  result before using it to increment?
 
 alpha = beta = 0
 alpha, beta = (sum(x) for x in zip( (alpha, beta),
 calculate(...) ) )
 
 Yeah, I came up with something similar, but it was so opaque I fell
 back to the more readable version I had above.  With only the two
 variables to increment in this case, the overhead of duplicating code
 doesn't seem as worth it as it might be if there were umpteen
 counters being returned as a tuple and umpteen corresponding
 variables being updated (at which point, it might make more sense to
 switch to another data structure like a dict).  Ah well.  Glad to see
 at least I'm not the only one stymied by trying to make it more
 pythonic while at least keeping it readable.
 
 -tkc

You can hide the complexity in a custom class:

 class T(tuple):
... def __add__(self, other):
... return T((a+b) for a, b in zip(self, other))
... 
 t = T((0, 0))
 for pair in [(1, 10), (2, 20), (3, 30)]:
... t += pair
... 
 t
(6, 60)

(If you are already using numpy you can do the above with a numpy.array 
instead of writing your own T.)

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Idiomatic Python for incrementing pairs

2013-06-08 Thread Jason Swails
On Sat, Jun 8, 2013 at 2:47 AM, Peter Otten __pete...@web.de wrote:

 You can hide the complexity in a custom class:

  class T(tuple):
 ... def __add__(self, other):
 ... return T((a+b) for a, b in zip(self, other))
 ...
  t = T((0, 0))
  for pair in [(1, 10), (2, 20), (3, 30)]:
 ... t += pair
 ...
  t
 (6, 60)

 (If you are already using numpy you can do the above with a numpy.array
 instead of writing your own T.)


I do this frequently when I want data structures that behave like vectors
but don't want to impose the numpy dependency on users. (Although I usually
inherit from a mutable sequence so I can override __iadd__ and __isub__).
It seemed overkill for the provided example, though...

All the best,
Jason
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Idiomatic Python for incrementing pairs

2013-06-08 Thread Terry Jan Reedy

On 6/8/2013 12:16 AM, Tim Chase wrote:

On 2013-06-08 07:04, Carlos Nepomuceno wrote:

alpha, beta = (1 if some_calculation(params) else 0, 1 if
other_calculation(params) else 0)


This one sets them to absolute values, rather than the incrementing
functionality in question:


   alpha += temp_a
   beta += temp_b


The actual code in question does the initialization outside a loop:

   alphas_updated = betas_updated = 0
   for thing in bunch_of_things:
 a, b = process(thing)
 alphas_updated += a
 betas_updated += b


I am pretty sure that this is the faster way to get the result.


and it just bugs me as being a little warty for having temp
variables when Python does things like tuple-unpacking so elegantly.


So use it ;-).


That said, as mentioned in a contemporaneous reply to Jason, I haven't
found anything better that is still readable.


The generalization of what you want is a mutable vector with an in-place 
augmented assignment version of element by element addition. That 
probably has been written. Nnmpy arrays do vector addition and maybe do 
it in-place also (I just do ot know). But here is a custom class for the 
problem you presented.


def process(val):
return val, 2*val

class Pair(list):
def __init__(self, a, b):
self.append(a)
self.append(b)
def inc(self, a, b):
self[0] += a
self[1] += b

pair = Pair(0, 0)
for val in [1,2,3]:
pair.inc(*process(val))

print(pair)

[6, 12]

This is cleaner but a bit slower than your in-lined version. I did not 
use __iadd__ and += because unpacking 'other' (here the process return) 
in the call does the error checking ('exactly two values') for 'free'.


--
Terry Jan Reedy



--
http://mail.python.org/mailman/listinfo/python-list


Re: Idiomatic Python for incrementing pairs

2013-06-07 Thread Jason Swails
On Fri, Jun 7, 2013 at 10:32 PM, Tim Chase python.l...@tim.thechases.comwrote:

 Playing around, I've been trying to figure out the most pythonic way
 of incrementing multiple values based on the return of a function.
 Something like

   def calculate(params):
 a = b = 0
 if some_calculation(params):
   a += 1
 if other_calculation(params):
   b += 1
 return (a, b)

   alpha = beta = 0
   temp_a, temp_b = calculate(...)
   alpha += temp_a
   beta += temp_b

 Is there a better way to do this without holding each temporary
 result before using it to increment?


alpha = beta = 0
alpha, beta = (sum(x) for x in zip( (alpha, beta), calculate(...) ) )

It saves a couple lines of code, but at the expense of readability IMO.  If
I was reading the first, I'd know exactly what was happening immediately.
 If I was reading the second, it would take a bit to decipher.  In this
example, I don't see a better solution to what you're doing.

All the best,
Jason
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Idiomatic Python for incrementing pairs

2013-06-07 Thread Chris Angelico
On Sat, Jun 8, 2013 at 12:32 PM, Tim Chase
python.l...@tim.thechases.com wrote:
   def calculate(params):
 a = b = 0
 if some_calculation(params):
   a += 1
 if other_calculation(params):
   b += 1
 return (a, b)

   alpha = beta = 0
   temp_a, temp_b = calculate(...)
   alpha += temp_a
   beta += temp_b

 Is there a better way to do this without holding each temporary
 result before using it to increment?

Can you pass the function a list with the appropriate values in them,
and have it return them via that?

  def calculate(params, sums):
if some_calculation(params):
  sums[0] += 1
if other_calculation(params):
  sums[1] += 1

  sums = [0, 0]
  calculate(..., sums)

Or use a dictionary if you'd rather they have names, either way.

ChrisA
-- 
http://mail.python.org/mailman/listinfo/python-list


RE: Idiomatic Python for incrementing pairs

2013-06-07 Thread Carlos Nepomuceno
alpha, beta = (1 if some_calculation(params) else 0, 1 if 
other_calculation(params) else 0)

 Date: Fri, 7 Jun 2013 21:32:39 -0500
 From: python.l...@tim.thechases.com
 To: python-list@python.org
 Subject: Idiomatic Python for incrementing pairs
 
 Playing around, I've been trying to figure out the most pythonic way
 of incrementing multiple values based on the return of a function.
 Something like
 
   def calculate(params):
 a = b = 0
 if some_calculation(params):
   a += 1
 if other_calculation(params):
   b += 1
 return (a, b)
 
   alpha = beta = 0
   temp_a, temp_b = calculate(...)
   alpha += temp_a
   beta += temp_b
 
 Is there a better way to do this without holding each temporary
 result before using it to increment?
 
 -tkc
 
 
 -- 
 http://mail.python.org/mailman/listinfo/python-list
  -- 
http://mail.python.org/mailman/listinfo/python-list


Re: Idiomatic Python for incrementing pairs

2013-06-07 Thread Tim Chase
On 2013-06-07 23:46, Jason Swails wrote:
 On Fri, Jun 7, 2013 at 10:32 PM, Tim Chase
def calculate(params):
  a = b = 0
  if some_calculation(params):
a += 1
  if other_calculation(params):
b += 1
  return (a, b)
 
alpha = beta = 0
temp_a, temp_b = calculate(...)
alpha += temp_a
beta += temp_b
 
  Is there a better way to do this without holding each temporary
  result before using it to increment?
 
 alpha = beta = 0
 alpha, beta = (sum(x) for x in zip( (alpha, beta),
 calculate(...) ) )

Yeah, I came up with something similar, but it was so opaque I fell
back to the more readable version I had above.  With only the two
variables to increment in this case, the overhead of duplicating code
doesn't seem as worth it as it might be if there were umpteen
counters being returned as a tuple and umpteen corresponding
variables being updated (at which point, it might make more sense to
switch to another data structure like a dict).  Ah well.  Glad to see
at least I'm not the only one stymied by trying to make it more
pythonic while at least keeping it readable.

-tkc


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Idiomatic Python for incrementing pairs

2013-06-07 Thread Tim Chase
On 2013-06-08 07:04, Carlos Nepomuceno wrote:
 alpha, beta = (1 if some_calculation(params) else 0, 1 if
 other_calculation(params) else 0)

This one sets them to absolute values, rather than the incrementing
functionality in question:

alpha += temp_a
beta += temp_b

The actual code in question does the initialization outside a loop:

  alphas_updated = betas_updated = 0
  for thing in bunch_of_things:
a, b = process(thing)
alphas_updated += a
betas_updated += b

and it just bugs me as being a little warty for having temp
variables when Python does things like tuple-unpacking so elegantly.
That said, as mentioned in a contemporaneous reply to Jason, I haven't
found anything better that is still readable.

-tkc



-- 
http://mail.python.org/mailman/listinfo/python-list


RE: Idiomatic Python for incrementing pairs

2013-06-07 Thread Carlos Nepomuceno
Oh! I really though you were just adding 1 or 0 to those variables. In clude 
the loop next time! ;)

You can accumulate the values by doing this instead:

alpha, beta = (alpha + (1 if some_calculation(params) else 0), beta + (1 if 
other_calculation(params) else 0))

 Date: Fri, 7 Jun 2013 23:16:22 -0500
 From: python.l...@tim.thechases.com
 To: carlosnepomuc...@outlook.com
 CC: python-list@python.org
 Subject: Re: Idiomatic Python for incrementing pairs
 
 On 2013-06-08 07:04, Carlos Nepomuceno wrote:
  alpha, beta = (1 if some_calculation(params) else 0, 1 if
  other_calculation(params) else 0)
 
 This one sets them to absolute values, rather than the incrementing
 functionality in question:
 
 alpha += temp_a
 beta += temp_b
 
 The actual code in question does the initialization outside a loop:
 
   alphas_updated = betas_updated = 0
   for thing in bunch_of_things:
 a, b = process(thing)
 alphas_updated += a
 betas_updated += b
 
 and it just bugs me as being a little warty for having temp
 variables when Python does things like tuple-unpacking so elegantly.
 That said, as mentioned in a contemporaneous reply to Jason, I haven't
 found anything better that is still readable.
 
 -tkc
 
 
 
  -- 
http://mail.python.org/mailman/listinfo/python-list