Onilol
Onilol

Reputation: 1339

Multiply number list by range of numbers

I'm trying to write code for a modulus 11 but I'm failing to make it more python-like.

As of now I'm using a weight and increasing it, checking when it reaches a number and then set it to it's original value.

Let's say I have a list of numbers 1..20 and I'd like to multiply them by 2,3,4,5,6,7,8,9,2,3,4,etc so that each index would be multiplied by an increasing number.

1x2, 2x3, 3x4, 4x5, 5x6, 6x7, 7x8, 8x9, 9x2, 10x3, etc..

Is there an elegant way to do this?

Unelegant way:

def mod11(list, max_weight=9):
    sum = 0
    weight = 2

    for item in reversed(list):
        sum += item * weight
        weight += 1

        if weight > max_weight:
            weight = 2

    mod = 11 - sum % 11

    if mod > 9:
        return 0

    else:
        return mod

Upvotes: 4

Views: 2054

Answers (6)

dawg
dawg

Reputation: 103774

You can use starmap and cycle from itertools.

First create a list of tuples to multiply together:

>>> from itertools import starmap, cycle
>>> li=zip(range(1,21), cycle(range(2,10)))
>>> li
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 2), (10, 3), (11, 4), (12, 5), (13, 6), (14, 7), (15, 8), (16, 9), (17, 2), (18, 3), (19, 4), (20, 5)]

Then use starmap and mul (from operator) to multiply:

>>> from operator import mul 
>>> list(starmap(mul, li))
[2, 6, 12, 20, 30, 42, 56, 72, 18, 30, 44, 60, 78, 98, 120, 144, 34, 54, 76, 100]

If you wanted a straight comprehension, you can do:

>>> [x*y for x, y in ((e+1, (e%8)+2) for e in range(20))]
[2, 6, 12, 20, 30, 42, 56, 72, 18, 30, 44, 60, 78, 98, 120, 144, 34, 54, 76, 100]

Upvotes: 1

Ozgur Vatansever
Ozgur Vatansever

Reputation: 52133

You don't have to worry about resetting the multiplier if you use itertools.cycle:

>>> itertools.cycle(range(2, 10))
2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, ...

so you can simplify your function like below:

from itertools import cycle

def mod11(lst, max_weight=9):
    multipliers = cycle(range(2, max_weight + 1))
    zipped = zip(lst, multipliers))
    summed = sum(a * b for a, b in zipped)
    mod = 11 - (summed % 11)
    return (0 if mod > 9 else mod)

Upvotes: 1

Anzel
Anzel

Reputation: 20553

A lot of good answers here already, and in case you would like to use numpy (usually good for this sort of thing), here's an alternative:

In [1]: import numpy as np

In [2]: a = np.arange(1, 21)  # like range in numpy array

In [3]: a - 1  # calculation performs per element wise... so will a * n
Out[3]:
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19])


In [4]: a * ((a - 1) % 8 + 2)  # directly translate the calculation
Out[4]:
array([  2,   6,  12,  20,  30,  42,  56,  72,  18,  30,  44,  60,  78,
        98, 120, 144,  34,  54,  76, 100])

Upvotes: 1

alecxe
alecxe

Reputation: 473833

You can use the current index to determine the multiplier:

>>> [(index % 8 + 2) * item for index, item in enumerate(range(1, 21))]
[2, 6, 12, 20, 30, 42, 56, 72, 18, 30, 44, 60, 78, 98, 120, 144, 34, 54, 76, 100]
#^        resets               ^            resets               ^

Or, you can "cycle" the sequence of multipliers and zip with the input sequence:

>>> from itertools import cycle
>>> [x * y for x, y in zip(range(1, 21), cycle(range(2, 10)))]
[2, 6, 12, 20, 30, 42, 56, 72, 18, 30, 44, 60, 78, 98, 120, 144, 34, 54, 76, 100]

Upvotes: 2

FlorianK
FlorianK

Reputation: 440

Ok, I am not quite sure if I understand your question correctly, since you talk about modulus 11, but also seem to use numbers from 2 up to and including 9.

But let's first start with writing the 1..20 as a list, that would be possible as follows:

list(range(1,21))    (This is if you want to include the 20)

Next, to turn some integer into a number between 2 and 9 you could do the following:

x -> x % 8 + 2

Combining these two, you could make a list comprehension:

[((x-1) % 8 + 2) * x for x in xrange(1,21)]

(the -1 is added to start the first number from 2 instead of from 3)

Upvotes: 1

Take_Care_
Take_Care_

Reputation: 2144

maybe oneliner :

s = map(lambda x : x*(x+1),list(range(1,20)))

basically map is core function used to make same operation on every element of table. first parameter is function which will be applied to every element. And If You want to remember generate another values used to multiplication maybe try some generator

Upvotes: 0

Related Questions