【问题标题】:How do I run a modulo conditional using one list on another list in python如何在python中使用另一个列表上的一个列表运行模条件
【发布时间】:2018-05-01 09:14:40
【问题描述】:

我只使用 python 大约 2 周,需要一些帮助。我正在尝试在两个不同大小的列表之间使用 mod (%) 函数。

n = 23 #user input, starting point for the code
listp = [2, 3, 5, 7, 11, 13]
listr = list(range((n-1)**2, n**2+1, 2))
listb = list(listr)  #I need to remove items from listr but if i do, it 
                     #crashes so I decided to copy it to listb in order to manipulate it

for k in listr:
    for i in listp[1:]:
        if k%i == 0:
            if k in listb:
                listb.remove(k)

这可行,但速度很慢,我想直接操作 listr 并且可以单独操作:

listr = [k for k in listr if i%listp[1] !=0]
listr = [k for k in listr if i%listp[2] !=0] 

底线是我想在 listr 中的每个 k 元素上使用 % 函数,使用 listp 中的每个 i 元素,并且只保留 listr 中的那些元素 !=0;我试过使用 numpy 和一个数组,但这也无济于事

【问题讨论】:

    标签: python numpy iteration conditional modulo


    【解决方案1】:

    您可以从找到any 这样的值的那一刻起停止。所以替换:

    for k in listr:
        for i in listp[1:]:
            if k%i == 0:
                if k in listb:
                    listb.remove(k)

    与:

    for k in listr:
        if any(k%i == 0 for i in listp[1:]):
            listb.remove(k)

    这已经产生了一些加速。但是list.remove 很慢,它可以在 O(n) 中运行。所以现在我们可以把它变成列表理解:

    listr = [k for k in listr <b>if not any(k%i == 0 for i in listp[1:])</b>]

    如果没有这样的模数条件,我们将数字添加到新的listr 列表中。 not any(p(x) for x in X) 可以重写为 all(not p(x) for x in X),所以我们可以在这里应用:

    listr = [k for k in listr if <b>all(k%i != 0</b> for i in listp[1:])]

    此外,我们还可以通过列出listp1 来节省一些周期:

    listp1 = listp[1:]
    listr = [k for k in listr if all(k%i != 0 for i in listp1)]

    因为现在我们只构建一个新列表一次。最后我们可以删除!= 0,因为整数的真实性是True,当且仅当值不等于0:

    listp1 = listp[1:]
    listr = [k for k in listr if all(k%i for i in listp1)]

    请注意,有比 埃拉托色尼筛法更快的方法。

    【讨论】:

    • 在构造新列表时,有什么原因不能在列表推导中使用listr代替listb
    • 哇,谢谢!我已经消化了第一部分,它几乎将运行时间减少了一半!我会继续插电。
    • 另外,我意识到我被困在 ops 的顺序上,因为我想减少 listr;但是一旦我用 listp 开始 for 循环,我就得到了我想要的:listr = [k for k in listr if i%listp[1] !=0] listr = [k for k in listr if i%listp[2] !=0] 而我写的是: for i in listp: listr = [k for k in listr if k%i !=0]
    • 好吧,哇,我再次使用了第二个建议,因为我在代码的两个区域使用了上面的编码,运行时间从两分钟多一点到 6 秒。顺便说一句,你有比埃拉托色尼筛法更快的方法的帖子或链接吗?
    • @spaceexplorer:见this Wikipedia article
    【解决方案2】:

    为了更快的操作,您可以尝试使用pandas,它在后台使用 numpy 并“将工作推到 C 级别”。看arange

    然后创建一个函数来完成您想要的工作,并将 apply 它用于您的 panda 数据结构的所有条目并捕获它:类似于

    final _list = pandas_struct.apply(function)

    您可以玩的一些示例如下: 多快可以接受?

    import numpy as np
    import pandas as pd
    
    n=23
    first = np.array([2, 3, 5, 7, 11, 13])
    second = np.arange((n-1)**2, n**2+1, 2)
    pand_second=pd.Series(second)
    
    def modme(num,div):
        if num % div  == 0:
            return num,'mod ok by',div
    
    [9]: pand_second.apply(modme, args=(3,))
    Out[9]: 
    0                    None
    1     (486, mod ok by, 3)
    2                    None
    3                    None
    4     (492, mod ok by, 3)
    5                    None
    6                    None
    7     (498, mod ok by, 3)
    8                    None
    9                    None
    10    (504, mod ok by, 3)
    11                   None
    12                   None
    13    (510, mod ok by, 3)
    14                   None
    15                   None
    16    (516, mod ok by, 3)
    17                   None
    18                   None
    19    (522, mod ok by, 3)
    20                   None
    21                   None
    22    (528, mod ok by, 3)
    dtype: object
    
    
    %timeit pand_second.apply(modme, args=(3,))
    81.3 µs ± 201 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    或者根本不使用 pandas :):

    import numpy as np
    
    n=23
    first = np.array([2, 3, 5, 7, 11, 13])
    second = np.arange((n-1)**2, n**2+1, 2)
    
    In [11]: [ second[ second % x == 0 ] for x in first ]
    Out[11]: 
    [array([484, 486, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508,
            510, 512, 514, 516, 518, 520, 522, 524, 526, 528]),
     array([486, 492, 498, 504, 510, 516, 522, 528]),
     array([490, 500, 510, 520]),
     array([490, 504, 518]),
     array([484, 506, 528]),
     array([494, 520])]
    
    
    %timeit [ second[ second % x == 0 ] for x in first ]
    15.6 µs ± 25.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    

    【讨论】:

    • 通过代码而不是通过概括来证明。 apply 未矢量化;所以会很慢。
    • 没有 dv,但即使是地球上最快的具有广泛并行化的超级计算机,最终也会被使用具有较低时间复杂度算法的智能手机超越。
    • @sharatc 重新阅读这些句子。我从来没有说过 apply 是矢量化的。你的代码在哪里显示它会“慢”:P
    • 我也听说过pandas,昨天刚拿numpy加载,pandas的加载难度是不是差不多?
    • @spaceexplorer - 我很容易加载 pandas - 也许输入一个新问题? - 我很乐意帮助你。熊猫很棒!
    猜你喜欢
    • 2010-11-03
    • 2021-08-09
    • 1970-01-01
    • 1970-01-01
    • 2014-11-19
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    相关资源
    最近更新 更多