查找数字运行,数字之间可自定义距离

时间:2018-06-10 03:28:52

标签: python list int list-comprehension

我有一个排序的整数列表,我发现想要查找此列表中的数字运行。我在寻找增加1的数字运行时看到了很多例子,但我也想查找数字运行,其中数字之间的差异是可自定义的。

例如,假设我有以下数字列表:

nums = [1, 2, 3, 6, 7, 8, 10, 12, 14, 18, 25, 28, 31, 39]

使用找到here的示例,我能够找到以下数字:

[[1, 2, 3], [6, 7, 8], [10], [12], [14], [18], [25], [28], [31], [39]]

但是,我想查找数字运行,其中两个数字之间的差异可能大于1.例如,我希望所有数字运行的距离小于或等于2.

[[1, 2, 3], [6, 7, 8, 10, 12, 14], [18], [25], [28], [31], [39]] 

或许我希望所有数字的距离都小于或等于3。

[[1, 2, 3, 6, 7, 8, 10, 12, 14], [18], [25, 28, 31], [39]]

这是我正在使用的函数,用于获取距离为1的数字运行。

def runs(seq, n):
    result = []
    for s in seq:
        if not result or s != result[-1][-1] + n:
            # Start a new run if we can't continue the previous one.
            result.append([])
        result[-1].append(s)
    return result

使用当前函数,如果我设置n=1,那么我会找到所有连续的数字序列。如果我设置了n=2,那么我只找到[8, 10, 12, 14]。如何修改此函数以查找小于或等于n的数字运行?

我希望能够做到这一点:

runs(num, 2)
[[1, 2, 3], [6, 7, 8, 10, 12, 14], [18], [25], [28], [31], [39]] 

3 个答案:

答案 0 :(得分:7)

使用for

进行迭代分组

我只是用这个来修复你的代码。为简化起见,您可以使用result初始化seq[0]

def runs(seq, n):
    result = [[seq[0]]]
    for s in seq[1:]:
        if s - result[-1][-1] > n:  # Keep it simple. Compare the delta.
            result.append([])
        result[-1].append(s)

    return result

>>> runs(nums, 1)
[[1, 2, 3], [6, 7, 8], [10], [12], [14], [18], [25], [28], [31], [39]]
>>> runs(nums, 2)
[[1, 2, 3], [6, 7, 8, 10, 12, 14], [18], [25], [28], [31], [39]]

pandas.GroupBy

如果你想获得幻想,你可以使用groupby成语,通过熊猫轻松实现。

import pandas as pd

def runs2(seq, n):
    s = pd.Series(seq)
    return s.groupby(s.diff().gt(n).cumsum()).apply(pd.Series.tolist).tolist()

>>> runs2(nums, 3)
[[1, 2, 3, 6, 7, 8, 10, 12, 14], [18], [25, 28, 31], [39]]

这里有两个基本要素:石斑鱼(你正在分组的谓语)和聚合函数(你将对每个组应用的函数)

石斑鱼是s.diff().gt(n).cumsum(),分解计算三件事:

  1. 使用seq
  2. diff中的元素差异
  3. 一个布尔掩码,指示diff是否大于n
  4. 执行累计和(或计数)以确定组
  5. 此操作的输出是

    s.diff().gt(n).cumsum()
    
    0     0
    1     0
    2     0
    3     1
    4     1
    5     1
    6     1
    7     1
    8     1
    9     2
    10    3
    11    4
    12    5
    13    6
    dtype: int64
    

    agg函数为pd.Series.tolist,并将任何系列转换为列表。这就是我们需要的,一个嵌套列表。

答案 1 :(得分:2)

def runs(nums, n):
    idx = np.flatnonzero(np.ediff1d(nums, n + 1, n + 1) > n)
    return [nums[i1:i2] for i1, i2 in zip(idx[:-1], idx[1:])]

然后,

>>> runs(nums, 3)
[[1, 2, 3, 6, 7, 8, 10, 12, 14], [18], [25, 28, 31], [39]]

答案 2 :(得分:1)

In [4]: def runs(seq, n):
   ...:     indexs = [i for i in range(len(seq)) if i==0 or seq[i]-seq[i-1]>n]
   ...:     return [seq[a:b] for a, b in zip(indexs, indexs[1:]+[len(seq)])]
   ...: 
   ...: 

In [5]: runs(nums, 3)
Out[5]: [[1, 2, 3, 6, 7, 8, 10, 12, 14], [18], [25, 28, 31], [39]]

In [6]: runs(nums, 2)
Out[6]: [[1, 2, 3], [6, 7, 8, 10, 12, 14], [18], [25], [28], [31], [39]]