8

I was hoping for an elegant or effective way to multiply sequences of integers (or floats).

My first thought was to try (1, 2, 3) * (1, 2, 2) would result (1, 4, 6), the products of the individual multiplications.

Though python isn't preset to do that for sequences. Which is fine, I wouldn't really expect it to. So what's the pythonic way to multiply (or possibly other arithmetic operations as well) each item in two series with and to their respective indices?

A second example (0.6, 3.5) * (4, 4) = (2.4, 14)

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
ThorSummoner
  • 16,657
  • 15
  • 135
  • 147
  • 2
    Perhaps you should look into `numpy`, multiplication operator when used with two `numpy.arrays` would behave like you expect. – Akavall Feb 17 '15 at 02:55
  • @Akavall, Would you be willing you post a numpy example? – ThorSummoner Feb 17 '15 at 02:57
  • 2
    @ThorSummoner Have you thought about accepting an answer? – Victor Castillo Torres Feb 17 '15 at 03:43
  • @VictorCastilloTorres That's tough, I don't feel qualified to say which if the three competing answers are most pythonic/elegant; Was hoping the upvotes would make that clear for me. I'm leaning tword thefourtheye's answer as of current due to its potential to work without an import, but that may not be a good reason at all. – ThorSummoner Feb 17 '15 at 17:17

5 Answers5

7

The simplest way is to use zip function, with a generator expression, like this

tuple(l * r for l, r in zip(left, right))

For example,

>>> tuple(l * r for l, r in zip((1, 2, 3), (1, 2, 3)))
(1, 4, 9)
>>> tuple(l * r for l, r in zip((0.6, 3.5), (4, 4)))
(2.4, 14.0)

In Python 2.x, zip returns a list of tuples. If you want to avoid creating the temporary list, you can use itertools.izip, like this

>>> from itertools import izip
>>> tuple(l * r for l, r in izip((1, 2, 3), (1, 2, 3)))
(1, 4, 9)
>>> tuple(l * r for l, r in izip((0.6, 3.5), (4, 4)))
(2.4, 14.0)

You can read more about the differences between zip and itertools.izip in this question.

Community
  • 1
  • 1
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
7

A simpler way would be:

from operator import mul

In [19]: tuple(map(mul, [0, 1, 2, 3], [10, 20, 30, 40]))
Out[19]: (0, 20, 60, 120)
Victor Castillo Torres
  • 10,581
  • 7
  • 40
  • 50
  • Nice, and can easily be extended to handle other binary operators. Although I think the OP might want `tuple(map(mul, seq1, seq2))`. – martineau Feb 17 '15 at 03:08
  • You're input and output don't match. Specifically, you should end up with a `tuple`, not a `list` ;-) – mgilson Feb 17 '15 at 03:32
6

If you are interested in element-wise multiplication, you'll probably find that many other element-wise mathematical operations are also useful. If that is the case, consider using the numpy library.

For example:

>>> import numpy as np
>>> x = np.array([1, 2, 3])
>>> y = np.array([1, 2, 2])
>>> x * y
array([1, 4, 6])
>>> x + y
array([2, 4, 5])
Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214
1

With list comprehensions the operation could be completed like

def seqMul(left, right):
    return tuple([value*right[idx] for idx, value in enumerate(left)])

seqMul((0.6, 3.5), (4, 4))
ThorSummoner
  • 16,657
  • 15
  • 135
  • 147
1
A = (1, 2, 3)
B = (4, 5, 6)    
AB = [a * b for a, b in zip(A, B)]

use itertools.izip instead of zip for larger inputs.

desired login
  • 1,138
  • 8
  • 15
  • Can you post an itertools example? This exact zip + list comprehension sort of answer has already been posted by @thefourtheye – ThorSummoner Feb 17 '15 at 02:56
  • @ThorSummoner, yes it is the same as the other answer, that was posted while I was writing my answer. for izip version `import itertools` and use `itertools.izip` instead of `zip`, otherwise it's exactly the same. – desired login Feb 17 '15 at 03:00