0

I'm trying to multiply two arrays without using numpy. But, I receive an error on the line "multi = a[i]*b[j]" stating that the index is out of range.

a = [1,2,3]
b = [4,5,6]

multi = [0,0,0,0,0,0,0,0]

for i in a:
    for j in b:
        multi = a[i]*b[j]
        append.multi(y)

print multi
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
  • 1
    ... and where did `y` come from? – Hugh Bothwell Jun 20 '12 at 19:44
  • Disregarding all the other issues with your code, why don't you want to use numpy to begin with? Because with numpy, the solution would be `a = numpy.array([[1, 2, 3]]);b = numpy.array([[4, 5, 6]]);multi = (a * b.T).flatten()` and while a non-numpy version using list comprehensions is faster for the three-element lists you used as an example, when you get to even just 10 elements per list the numpy version will be faster. – JAB Jun 20 '12 at 21:29
  • (On my computer: with 3 elements per list, it takes about 9 seconds for the numpy version and 3 seconds for the non-numpy version, while with 10 per list it takes about 10 seconds for the numpy version and 16 seconds for the non-numpy one.) – JAB Jun 20 '12 at 21:29

4 Answers4

4

Lets start with what you were trying. The for loop:

a = [1,2,3]
b = [4,5,6]

ab = []

for x in a:
    for y in b:
        ab.append(x * y)

print(ab)

[4, 5, 6, 8, 10, 12, 12, 15, 18]

Now, I would suggest you have a read here python data structures

Once you understand how to use a for loop, understanding list comprehensions is easy.

The are the same for loop, but but the results go straight into a list. this is nice. In-fact it is so nice that nearly everybody does it this way.

a = [1,2,3]
b = [4,5,6]

ab = [ x * y for x in a for y in b ]

print(ab)

[4, 5, 6, 8, 10, 12, 12, 15, 18]

so, instead of for ... ab.append(x * y) we write [ x * y for ... ]

now if the code was written like this:

ab = ( x * y for x in a for y in b )

it would make it a generator. Lots of people use these as well. Think of these as lazy lists. You can put things in it, but it is not evaluated until you try and do something with it.

print(ab)
<generator object <genexpr> at 0x4d7058>

print( list(ab) )
[4, 5, 6, 8, 10, 12, 12, 15, 18]

if you 'were' trying to solve this using the indexes, I would probably use:

[a[x] * b[y] for x,_a in enumerate(a) for y,_b in enumerate(b)]

you can also do fun things like:

from operator import mul

a = [1,2,3]
b = [4,5,6]

ab = list(map(mul, a,b))

print(ab)

[4, 10, 18]

if you used:

ab = map(mul, a,b)

you would create a map object... which is very much the same as the < generator >.

print(ab)
>>> <map object at 0x4d4eb0>

print( list(ab) )
>>> [4, 10, 18]

or if you had three lists:

a = [1,2,3]
b = [4,5,6]
c = [7,8,9]

abc = list(map(lambda x,y,z: x * y * z, a,b,c))

print(abc)

[28, 80, 162]

and if you really wanted to you could do:

from itertools import product
from functools import reduce
from operator import mul

a = [1,2,3]
b = [4,5,6]

ab = list(map(lambda x: reduce(mul,x), product(a,b)))
--or--
ab = list(map(lambda x: mul(*x), product(a,b)))

print(ab)

[4, 5, 6, 8, 10, 12, 12, 15, 18]
beoliver
  • 5,579
  • 5
  • 36
  • 72
  • Huge +1...I didn't know map could take n parallel arrays of positional arguments. – twneale Jun 20 '12 at 20:00
  • 1
    As 'un-pythonic' as map, reduce ... are. They make me happy :) – beoliver Jun 20 '12 at 20:05
  • 1
    They aren't unpythonic at all when used properly, as there are certain things you can do with map and reduce that can't be done as easily with other functions and language features Python has. For example, list/generator/etc. comprehensions get very unwieldy when using many iterables as input. "[P]racticality beats purity," after all. – JAB Jun 20 '12 at 20:33
  • Why is `map` preferable to the comprehension `[x*y for x,y in zip(a,b)]`? Its shorter than the map (even if you remove whitespace) and comprehensions are almost always considered more pythonic. – Aaron Dufour Jun 20 '12 at 21:08
  • No time at the moment; I might respond properly tomorrow morning if someone else hasn't already. – JAB Jun 20 '12 at 21:30
  • 1
    @AaronDufour, I don't think anyone said that map is preferable to your suggestion. But your question seems a bit like this: if everyone agrees that snakes like fuit-baskets more than fishing-nets... why should a snake like a fishing-net more than a fruit-basket with a trout in it? – beoliver Jun 20 '12 at 23:19
  • you must also remebder that operator.mul can just be imported as mul -- so `list(map(mul,x,y))` is in fact shorter than `[x*y for x,y in zip(a,b)]` ... if your into that, and if you didn't need the list straight away, `map(mul,x,y)` is even shorter than `(x*y for x,y in zip(a,b))` – beoliver Jun 20 '12 at 23:37
  • @ThemanontheClaphamomnibus Concise functional programming is never unpythonic. Also, map etc. can be significantly faster that list comprehensions depending on the situation. – twneale Jun 27 '12 at 14:49
  • @ThemanontheClaphamomnibus I don't think that quite captures it; your snake parable is nonsense (which I think was the point), while I had a genuine question about why we would answer a question from a beginner with the conceptually `map` over a much simpler list comprehension. – Aaron Dufour Jun 27 '12 at 21:48
3

You have numerous errors in your code and should read the Python tutorial.

for i in a iterates over the elements of a, not their indices. So you want i*j, not a[i]*b[j]. Also, append.multi(y) is not the right way to append to a list, and you don't define any variable called y anyway, so it's not clear what you're trying to do. Read the tutorial.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
2

Use a list comprehension:

a = [1,2,3]
b = [4,5,6]
m = [x * y for x in a for y in b]
print m
>>> [4, 5, 6, 8, 10, 12, 12, 15, 18]
twneale
  • 2,836
  • 4
  • 29
  • 34
0

for i in a doesn't return indices, it returns values. You should do this:

for i in a: for j in b: multi=i*j ...
zmbq
  • 38,013
  • 14
  • 101
  • 171