如何在列表理解中执行多项操作

时间:2018-10-05 17:08:18

标签: python list operation

L = [random.randint(0,50) for i in range(5) random.randint(0,12) for i in range(2)]

如何获取(0,50)之间的5个随机数,然后选择(0,12)之间的2个随机数?

8 个答案:

答案 0 :(得分:8)

您可以根据randint()的值将第二个参数更改为i

[randint(0, 50 if i < 5 else 12) for i in range(7)]

50 if i < 5 else 12表达式将更改最后两次迭代传递给random.randint()的内容。

您可以在其中输入更多的变化形式。列表推导是一堆循环和if过滤器,它们重复执行前面的表达式。根据表达式中的迭代值,有很多方法可以将变元变种到函数调用中

例如,您可以将这些参数记录在functools.partial() objects中:

from functools import partial
from random import randint

rint50 = partial(randint, 0, 50)
rint12 = partial(randint, 0, 12)
[rint() for rint in [rint50] * 5 + [rint12] * 2]

可能性是无限的。 Lambdas,randint(0, upperbound)randint(*args)这个函数会根据调用的频率等不同而改变结果。但是,我不认为其中任何一个实际上更具可读性或可理解性。

在这种情况下,只有7个值,我将两个列表连接起来:

[randint(0, 50) for _ in range(5)] + [randint(0, 12) for _ in range(2)]

因为它更干净,更易读。在此处创建包含两个列表理解结果的第三个列表的性能开销很小,可以忽略不计。

答案 1 :(得分:4)

可能是这样,将2个列表串联在一起:

from random import randint
my_list = [randint(0,50) for i in range(5)] + [randint(0,12) for i in range(2)]

答案 2 :(得分:3)

请勿重复使用名称list。一种方法是遍历边界的迭代,并将其发送到randint

from random import randint

lst = [randint(*bounds) for bounds in [(0, 50)]*5 + [(0, 12)]*2]

您还可以使用itertools.chainitertools.repeat来避免建立边界列表

lst = [randint(*bounds) for bounds in chain(repeat((0, 50), 5), repeat((0, 12), 2))]

答案 3 :(得分:1)

import random
l = [random.randint(0,50) for i in range(5)]
l.extend([random.randint(0,12) for i in range(2)])

print(l)

答案 4 :(得分:1)

这是另一个避免每次迭代都进行if测试的变体。它还使用randrange,效率比randint略高。

from random import randrange
lst = [randrange(hi) for num, hi in ((5, 51), (2, 13)) for _ in range(num)]
print(lst)

典型输出

[10, 31, 46, 25, 23, 6, 5]

这等效于

lst = []
for num, hi in ((5, 51), (2, 13)):
    for _ in range(num):
        lst.append(randrange(hi))

外部循环选择num,子列表中的项数和hi子列表的随机范围的大小;内部循环会在所需范围内生成所需数量的随机数。


FWIW,这是一些timeit代码,用于比较已提交的各种算法。它还验证了在给定相同的随机种子时它们是否产生相同的结果。我的简单验证代码使用eval,因此它只能测试表达式,而不能测试语句,因此不能测试jpp或Abhishek的代码。此外,由于jpp的Numpy代码使用了不同的播种算法,因此无论如何都会给出不同的结果。有关timeit的功能以及如何解释结果的信息,请参见timeit文档。

from timeit import Timer
import random
from random import randint, randrange, seed
from itertools import chain, repeat, starmap
from functools import partial
import numpy as np

imports = 'random, randint, randrange, seed, chain, repeat, starmap, partial, np'

commands = (
    ('Martijn', '', '[randint(0, 50 if i < 5 else 12) for i in range(7)]'),
    ('Martijn_partial', 
        'rint50 = partial(randint, 0, 50); rint12 = partial(randint, 0, 12)', 
        '[rint() for rint in [rint50] * 5 + [rint12] * 2]'
    ),
    ('Patrick', '', '[randint(*bounds) for bounds in [(0, 50)]*5 + [(0, 12)]*2]'),
    ('Patrick_chain', '', 
        '[randint(*bounds) for bounds in chain(repeat((0, 50), 5), repeat((0, 12), 2))]'
    ),
    ('Ralf', '', '[randint(0,50) for i in range(5)] + [randint(0,12) for i in range(2)]'),
    ('Abhishek', '', 'l = [random.randint(0,50) for i in range(5)];'
        'l.extend([random.randint(0,12) for i in range(2)])'
    ),
    ('PM 2Ring', '', '[randrange(hi) for num, hi in ((5, 51), (2, 13)) for _ in range(num)]'),
    ('jpp', '', 'A = np.zeros(7); ' 
        'A[:5] = np.random.randint(0, 20, 5); A[5:] = np.random.randint(0, 12, 2)'
    ),
    ('Tanmay jain', '', 
        '[random.randint(0,50) if i < 5 else random.randint(0,12) for i in range(7)]'
    ),
    ('juanpa', '', '[random.randint(a,b) for args in (((0,50) for _ in range(5)),' 
        '((0, 12) for _ in range(2))) for a, b in args]'
    ),
    ('juanpa_starmap', '', 'list(starmap(random.randint,'
        'chain(repeat((0,50),5), repeat((0,12),2))))'
    ),
)

def verify():
    for name, setup, cmd in commands:
        if name in ('jpp', 'Abhishek'):
            continue
        seed(17)
        if setup:
            exec(setup)
        print('{:16}: {}'.format(name, eval(cmd)))
    print()

def time_test(loops):
    timings = []
    print('loops =', loops)
    for name, setup, cmd in commands:
        setup = 'from __main__ import ' + imports + ';' + setup
        t = Timer(cmd, setup=setup)
        result = sorted(t.repeat(3, loops))
        timings.append((result, name))
    timings.sort()
    for result, name in timings:
        print('{:16} : {}'.format(name, result))

verify()
time_test(5000)

典型输出

Martijn         : [33, 26, 19, 23, 18, 2, 12]
Martijn_partial : [33, 26, 19, 23, 18, 2, 12]
Patrick         : [33, 26, 19, 23, 18, 2, 12]
Patrick_chain   : [33, 26, 19, 23, 18, 2, 12]
Ralf            : [33, 26, 19, 23, 18, 2, 12]
PM 2Ring        : [33, 26, 19, 23, 18, 2, 12]
Tanmay jain     : [33, 26, 19, 23, 18, 2, 12]
juanpa          : [33, 26, 19, 23, 18, 2, 12]
juanpa_starmap  : [33, 26, 19, 23, 18, 2, 12]

loops = 5000
jpp              : [0.23938178099342622, 0.24184146700281417, 0.3152835669970955]
PM 2Ring         : [0.26918871099769603, 0.27244400099880295, 0.2916741489971173]
Patrick          : [0.34155847399961203, 0.34415175200410886, 0.3531294650019845]
juanpa_starmap   : [0.3417540490045212, 0.34329504700144753, 0.3438059809996048]
Martijn          : [0.3509639670010074, 0.362117896998825, 0.547288200003095]
Martijn_partial  : [0.3511254819968599, 0.35262946599686984, 0.39430355399963446]
Patrick_chain    : [0.3541102219969616, 0.3545923809942906, 0.3555165420038975]
Tanmay jain      : [0.3558294050017139, 0.5510739650053438, 0.7693202439986635]
Ralf             : [0.3678122450000956, 0.44522786799643654, 0.44827762299973983]
juanpa           : [0.4089203829935286, 0.41227930299646687, 0.42410747800022364]
Abhishek         : [0.4811078249986167, 0.4942625819967361, 0.6255962599971099]

如您所见,jpp的Numpy代码是最快的。我希望如果我们生成更长的数字列表,速度差异会更加明显。

这些计时是在古老的32位单核2GHz机器上执行的,该机器在Debian衍生发行版上运行Python 3.6.0。 YMMV。


以下是在相同范围内生成50 + 20 = 70个值的列表(或数组)的时间。

loops = 500
jpp              : [0.025625186994147953, 0.025764200996491127, 0.03122780400008196]
PM 2Ring         : [0.21989007600495825, 0.2200367909972556, 0.22065802400175016]
juanpa_starmap   : [0.3094131350007956, 0.3110805670003174, 0.31563361900043674]
Patrick_chain    : [0.3122365829985938, 0.31262181099737063, 0.3137894630053779]
Patrick          : [0.3130071220002719, 0.31769691400404554, 0.3179219129960984]
Ralf             : [0.31566168300196296, 0.3157304769993061, 0.3234770689959987]
Martijn          : [0.3193310350034153, 0.3275600470005884, 0.35491854500287445]
Martijn_partial  : [0.321399387998099, 0.3226969290044508, 0.32442738999816356]
Abhishek         : [0.32655813400197076, 0.3363869300010265, 0.3657162370000151]
Tanmay jain      : [0.32833286200184375, 0.33107244400162017, 0.39565577400207985]
juanpa           : [0.35968791200139094, 0.3754627199959941, 0.3933205349967466]

答案 5 :(得分:0)

如果您很高兴使用第三方库,则可以通过NumPy:

import numpy as np

np.random.seed(0) # for consistency / testing

A = np.zeros(7)
A[:5] = np.random.randint(0, 20, 5)
A[5:] = np.random.randint(0, 12, 2)

array([ 12.,  15.,   0.,   3.,   3.,   7.,   9.])

这种方法的好处是,内存预分配在较大的数组中显而易见。

答案 6 :(得分:0)

since you want to pick 5 random values from 0 - 50( exclusive)
i = 0...4
and then you want to pick 2 random values from 0 - 12( exclusive)
i = 5 6


lst = [random.randint(0,50) if i < 5 else random.randint(0,12) for i in range(7)]

print(lst) # [7, 10, 40, 4, 38, 1, 5]

答案 7 :(得分:0)

可以使用列表理解并且仅使用内置功能,有些怪异,例如:

index.html

也许,如果您想使用itertools,可以执行以下操作:

>>> result = [
...     random.randint(a,b)
...     for args in (((0,50) for _ in range(5)), ((0, 12) for _ in range(2)))
...     for a, b in args
... ]
>>> result
[33, 38, 19, 9, 47, 0, 8]

这两种方法都很难阅读和简单。相反,我个人会使用两个for循环,即朴素的方法。这将是高效,简单和可读的。除了showboating,我认为在生产代码中上述方法没有任何优势。