Python 根据元素之间的相互关系筛选出列表中的元素

Python 根据元素之间的相互关系筛选出列表中的元素,python,list,for-loop,Python,List,For Loop,我正在处理一个有趣的python问题: 给定一个整数、细菌和正整数常量K的列表,如果有两个元素i和j满足以下条件: j < i <= j + K 最终结果应为: [42,102,55] 因此,应返回3 同样地 micro_world([101,53,42,102,101,55,54],1)将给我一个3的结果 微世界([20,15,10,15,20,25],5)会给我一个1的结果 我正在考虑使用列表理解来过滤掉不符合上述标准的元素,从而得到我想要的元素。但我不确定如何继续,因为

我正在处理一个有趣的python问题:

给定一个整数、细菌和正整数常量K的列表,如果有两个元素i和j满足以下条件:

j < i <= j + K
最终结果应为:

 [42,102,55] 
因此,应返回3

同样地

micro_world([101,53,42,102,101,55,54],1)
将给我一个3的结果

微世界([20,15,10,15,20,25],5)
会给我一个1的结果

我正在考虑使用列表理解来过滤掉不符合上述标准的元素,从而得到我想要的元素。但我不确定如何继续,因为它涉及列表中每个元素之间的关系

result = [ i for i in bacteria if ... ]
我的if声明应该使用什么

如果这不是一个好办法,我该怎么办

谢谢

编辑: 这两个答案都为我提供了非常好的指导。但是细菌列表中的重复值只有一个小问题。例如,如果输入

bacteria = [3, 3]

即使这只是一个区块,结果也应该是2,因为3!>3因此两者都不能删除。

这里有一个使用
numpy
的解决方案:

import numpy as np

def micro_world(bacteria, K):
    # convert bacteria list to a numpy array:
    bacteria = np.asarray(bacteria)

    # sort array and remember the indices used for sorting:
    sarg = np.argsort(bacteria)
    sortedbac = bacteria[sarg]

    # compute differences between adjacent elements:
    diff = np.ediff1d(sortedbac, K + 1)

    # throw away elements that are too close to neighbors
    # (find indices of the elements to keep):
    idx = np.flatnonzero(diff > K)

    # create a new list that meets selection criteria:
    return bacteria[np.sort(sarg[idx])]

下面是一个“纯”Python实现:

def micro_world(bacteria, K):
    # sort array and remember the indices used for sorting:
    sarg = [i[0] for i in sorted(enumerate(bacteria), key=lambda x: x[1])]
    sortedbac = [bacteria[i] for i in sarg]

    # compute differences between adjacent elements:
    diff = [j - i for i, j in zip(sortedbac[:-1], sortedbac[1:])] + [K + 1]

    # throw away elements that are too close to neighbors
    # (find indices of the elements to keep):
    idx = [i for i, v in enumerate(diff) if v > K]

    # create a new list that meets selection criteria:
    return [bacteria[i] for i in sorted([sarg[i] for i in idx])]

如果您只对元素的数量感兴趣,而对元素本身不感兴趣,则可以修改第二个版本,如下所示:

def micro_world(bacteria, K):
    sortedbac = sorted(bacteria)
    diff = [j - i for i, j in zip(sortedbac[:-1], sortedbac[1:])] + [K + 1]
    return sum(1 for v in diff if v > K)
numpy
版本将变成:

def micro_world(bacteria, K):
    return np.sum(np.ediff1d(np.sort(bacteria), K + 1) > K)

实际上,您正试图将数字列表分组为块,其中每个数字都小于
k
,与该块中的另一个数字相距甚远。因为我不擅长解释,让我们看一个例子:

bacteria = [101, 53, 42, 102, 101, 55, 54]
K = 1
首先,我们要对该列表进行排序,以便按大小排列数字:

[102, 101, 101, 55, 54, 53, 42]
现在,我们迭代列表,每当较大的细菌不能吞下较小的细菌时,就创建一个新的数字块:

[[102, 101, 101], [55, 54, 53], [42]]
最后,我们计算块的数量,从而得到期望的结果:3

代码:

def micro_world(细菌,k):
#对列表进行向下排序
细菌=已分类(细菌,反向=真)
#循环浏览列表,但跳过所有“吞食”的细菌
i=0
结果=0
而我(细菌):
细菌大小=细菌[i]

#虽然数字之间的差异是@timgeb OK,但我会尝试从这个角度来做。但我有点看不出我的问题是怎么和它标记的问题重复的。我专门创建了一个克隆来避免这种情况。谢谢。如果您仍在列表中迭代要删除的值,那么创建多少副本都无关紧要。@Aran Fey谢谢。我将尝试使用列表理解过滤它。有关于它应该是什么样子的提示吗?我正在试图找出如何将I和j都放入理解if语句列表中。@Aran Fey我的问题现在有效吗?谢谢。我不认为有一个好的方法来解决这个问题。简单的解决方法是创建
细菌
列表的另一个副本并对其进行迭代。但是(我认为)有更好的解决方案,比如对列表排序,然后只迭代一次,丢弃不需要的元素。非常感谢。我没有想到这种方法,你的回答确实为我提供了一个新的视角。但这种方法似乎不能很好地处理重复值。例如,如果
细菌=[5,5]
那么'i!>因此,将有两个块作为结果,但您的代码将产生1。有办法解决这个问题吗?再次感谢。@BowenLiu你是说重复的数字会产生额外的块?但是,
micro_world([20,15,10,15,20,25],5)
的输出不是3吗,因为15和20是重复的?我不太明白这里的逻辑。对不起,我真的不擅长解释事情。这种情况很好,因为重复的15将被消除,因为15<20非常感谢您的帮助。只是有机会尝试一下。只是为了确保:
break
将停止当前迭代并返回到更高级别(我确定我在这里没有使用正确的术语,我的意思是像前面的缩进一样),对吗?在这种情况下,您是如何决定while循环优于for循环的?谢谢again@BowenLiu没错,是的。我使用
while
循环,因为两个循环共享相同的索引
I
。使用两个
for
循环更难做到这一点。
[[102, 101, 101], [55, 54, 53], [42]]
def micro_world(bacteria, k):
    # sort the list descendingly
    bacteria = sorted(bacteria, reverse=True)

    # loop over the list but skip all the "swallowed" bacteria
    i = 0
    result = 0
    while i < len(bacteria):
        bacterium_size = bacteria[i]

        # while the difference between the numbers is <= k, the smaller
        # bacterium is swallowed
        bigger_bacterium_exists = False
        while i+1 < len(bacteria):
            difference = bacterium_size - bacteria[i+1]

            # if the difference is too big, it can't be swallowed
            if difference > k:
                break

            # if there are two bacteria of the same size, they can't swallow
            # each other. But if a bigger bacterium exists, it can swallow
            # them both
            if difference == 0 and not bigger_bacterium_exists:
                break

            # all conditions are met, the bacterium is swallowed
            bacterium_size = bacteria[i+1]
            i += 1
            bigger_bacterium_exists = True

        # at this point, the bacterium has swallowed everything it can.
        # Increment the result counter and move on to the next bacterium.
        result += 1
        i += 1

    return result