14

Let's say I have a

class Rectangle(object):                                               
def __init__(self, length, width, height=0):                                                   
    self.l = length                                               
    self.w = width                                                
    self.h = height                                               
    if not self.h:                                                     
        self.a = self.l * self.w                                       
    else:                                                              
        from itertools import combinations                            
        args = [self.l, self.w, self.h]                                
        self.a = sum(x*y for x,y in combinations(args, 2)) * 2
                 # original code:
                 # (self.l * self.w * 2) + \                            
                 # (self.l * self.h * 2) + \                            
                 # (self.w * self.h * 2)                                
        self.v = self.l * self.w * self.h                                           

What's everyone's take on line 12?

self.a = sum(x*y for x,y in combinations(args, 2)) * 2 

I've heard that explicit list index references should be avoided.

Is there a function I can use that acts like sum(), but only for multiplication?

Thanks for the help everyone.

yurisich
  • 6,991
  • 7
  • 42
  • 63

5 Answers5

15

Since this is in the top Google results, I'll just add that since Python 3.8, you can do :

from math import prod
t = (5, 10)
l = [2, 100]
prod(t) # 50
prod(l) # 200
n49o7
  • 476
  • 7
  • 8
  • Even though this doesn't actually answer my question, it matches the title, and should be the easiest to find in a quick search. To be completely accurate, though, I would want to sum these product results together: `sum(map(math.prod, itertools.combinations([l, w, h], 2))) * 2` – yurisich Dec 03 '20 at 00:21
  • Haha thanks for maintaining this question 9 years later! A slightly shorter version: `2*(h*w+h*l+l*w)`. `itertools.combinations` is indeed useful for higher dimensions, but `math.prod` doesn't seem to help much. – n49o7 Dec 06 '20 at 14:28
11

I don't see any problem with using indexes here:

sum([x[0] * x[1] for x in combinations(args, 2)])

If you really want to avoid them, you can do:

sum([x*y for x,y in combinations(args, 2)])

But, to be honest I would prefer your commented out version. It is clear, readable and more explicit. And you don't really gain much by writing it as above just for three variables.

Is there a function I can use that acts like sum(), but only for multiplication?

Built-in? No. But you can get that functionality rather simply with the following:

In : a=[1,2,3,4,5,6]

In : from operator import mul

In : reduce(mul,a)
Out: 720
Avaris
  • 35,883
  • 7
  • 81
  • 72
  • 5
    reduce does not exist any more from python 3.0+ – Serdalis Oct 22 '11 at 19:40
  • +1 and answer for the `reduce(mul, l)` tip. I agree, the first draft was clearer, I was just looking for a one liner to expand my list comprehension...comprehension. `:D` – yurisich Oct 22 '11 at 19:48
  • 1
    @Serdalis: Correct, thanks for the tip. But there is `functools.reduce`, which is same actually. – Avaris Oct 22 '11 at 20:01
6

In short, just use np.prod

import numpy as np
my_tuple = (2, 3, 10)
print(np.prod(my_tuple))  # 60

Which is in your use case

np.sum(np.prod(x) for x in combinations(args, 2))

np.prod can take both lists and tuple as a parameter. It returns the product you want.

cwilmot
  • 119
  • 1
  • 5
0

you can do:

from operator import mul
sum(reduce(mul,combinations(args, 2)))

but I think it just makes things less readable.

However, before summing you are actually building the list of multiplication sum([...]).

self.a = sum([(x[0] * x[1] * 2) for x in combinations(args, 2)])

This is not needed, simply do:

self.a = sum(x * y * 2 for x,y in combinations(args, 2))
log0
  • 10,489
  • 4
  • 28
  • 62
  • I see too many left brackets in both of your examples. I ran my code in 2.6, it compiled for me. I'll try the `for x, y in` bit, though. – yurisich Oct 22 '11 at 19:38
  • I fixed my typo, you should fix yours :) there is problem here `sum(([x[0]...` – log0 Oct 22 '11 at 19:47
  • Why doesn't SO come with an interpreter for noobs like me? Good eye. – yurisich Oct 22 '11 at 19:54
  • @Ugo: `(x[0] * x[1] * 2)` is not a tuple. It is same as `x[0] * x[1] * 2`. You need to put `,` in order to make a tuple of length one, e.g. `(2,)`. – Avaris Oct 22 '11 at 20:04
0

I did make a very simple definition of product; helpful for "calculating the product of a tuple"

def product(tuple1):
    """Calculates the product of a tuple"""
    prod = 1
    for x in tuple1:
        prod = prod * x
    return prod

Might be a more elegant way to do it but this seems to work OK. Presumably it would work on a list just as well.

iMom0
  • 12,493
  • 3
  • 49
  • 61
Allen
  • 1