Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

correct style for element-wise operations on lists without numpy (python)

I would like to operate on lists element by element without using numpy, for example, i want add([1,2,3], [2,3,4]) = [3,5,7] and mult([1,1,1],[9,9,9]) = [9,9,9], but i'm not sure which way of doing is it considered 'correct' style.

The two solutions i came up with were

def add(list1,list2):
    list3 = []
    for x in xrange(0,len(list1)):
        list3.append(list1[x]+list2[x])
    return list3

def mult(list1, list2):
    list3 = []
    for x in xrange(0,len(list1)):
        list3.append(list1[x]*list2[x])
    return list3

def div(list1, list2):
    list3 = []
    for x in xrange(0,len(list1)):
        list3.append(list1[x]/list2[x])
    return list3

def sub(list1, list2):
    list3 = []
    for x in xrange(0,len(list1)):
        list3.append(list1[x]-list2[x])
    return list3

where each operator is given a separate function

and

def add(a,b)
    return a+b
def mult(a,b)
    return a*b
def div(a,b)
    return a/b
def sub(a,b)
    return a-b
def elementwiseoperation(list1, list2, function):
    list3 = []
    for x in xrange(0,len(list1)):
        list3.append(function(list1[x],list2[x]))
    return list3

where all the basic functions are defined, and I have a separate function to use them on each element. I skimmed through PEP8, but didn't find anything directly relevant. Which way is better?

like image 695
shimao Avatar asked Dec 08 '22 14:12

shimao


1 Answers

The normal way to do this would be to use map or itertools.imap:

import operator
multiadd = lambda a,b: map(operator.add, a,b)
print multiadd([1,2,3], [2,3,4]) #=> [3, 5, 7]

Ideone: http://ideone.com/yRLHxW

map is a c-implemented version of your elementwiseoperation, with the advantage of having the standard name, working with any iterable type and being faster (on some versions; see @nathan's answer for some profiling).

Alternatively, you could use partial and map for a pleasingly pointfree style:

import operator
import functools

multiadd = functools.partial(map, operator.add)
print multiadd([1,2,3], [2,3,4]) #=> [3, 5, 7]

Ideone: http://ideone.com/BUhRCW

Anyway, you've taken the first steps in functional programming yourself. I suggest you read around the topic.

As a general matter of style, iterating by index using range is generally considered the wrong thing, if you want to visit every item. The usual way of doing this is simply to iterate the structure directly. Use zip or itertools.izip to iterate in parallel:

for x in l:
    print l

for a,b in zip(l,k):
    print a+b

And the usual way to iterate to create a list is not to use append, but a list comprehension:

[a+b for a,b in itertools.izip(l,k)]
like image 199
Marcin Avatar answered May 21 '23 18:05

Marcin