【问题标题】:Replace a list of numbers with flat sub-ranges用平面子范围替换数字列表
【发布时间】:2017-08-28 16:58:18
【问题描述】:

给定一个数字列表,如下所示:

lst = [0, 10, 15, 17]

我想要一个列表,其中包含来自i -> i + 3 的所有i 中的lst 的元素。如果有重叠的范围,我希望它们合并。

所以,对于上面的例子,我们首先得到:

[0, 1, 2, 3,     10, 11, 12, 13,     15, 16, 17, 18,   17, 18, 19, 20]

但对于最后 2 组,范围重叠,因此在合并它们时,您有:

[0, 1, 2, 3,     10, 11, 12, 13,     15, 16, 17, 18,     19, 20]

这是我想要的输出。

这是我想到的:

from collections import OrderedDict

res = list(OrderedDict.fromkeys([y for x in lst for y in range(x, x + 4)]).keys())
print(res) = [0, 1, 2, 3, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20]

但是,这很慢 (10000 loops, best of 3: 56 µs per loop)。如果可能的话,我想要一个 numpy 解决方案,或者比这更快的 python 解决方案。

【问题讨论】:

  • 原始元素是否保证排序?
  • @Ev.Kounis 是的。保证。
  • @Coldspeed 然后你可以使用它。投射到set,然后再次投射到sorting,如果它让它更快的话。
  • @ChristianDean 哦,对不起,我在 python2 上运行这个。
  • @cᴏʟᴅsᴘᴇᴇᴅ 啊,那我错了。我没有意识到版本之间存在差异。我很少使用 Python 2。

标签: python list numpy


【解决方案1】:

方法#1:一种基于broadcasted求和然后使用np.unique获取唯一数字的方法 -

np.unique(np.asarray(lst)[:,None] + np.arange(4))

方法 #2: 另一种基于广播求和然后屏蔽 -

def mask_app(lst, interval_len = 4):
    arr = np.array(lst)
    r = np.arange(interval_len)
    ranged_vals = arr[:,None] + r
    a_diff = arr[1:] - arr[:-1]
    valid_mask = np.vstack((a_diff[:,None] > r, np.ones(interval_len,dtype=bool)))
    return ranged_vals[valid_mask]

运行时测试

原始方法-

from collections import OrderedDict
def org_app(lst):
    list(OrderedDict.fromkeys([y for x in lst for y in range(x, x + 4)]).keys())

时间安排 -

In [409]: n = 10000

In [410]: lst = np.unique(np.random.randint(0,4*n,(n))).tolist()

In [411]: %timeit org_app(lst)
     ...: %timeit np.unique(np.asarray(lst)[:,None] + np.arange(4))
     ...: %timeit mask_app(lst, interval_len = 4)
     ...: 
10 loops, best of 3: 32.7 ms per loop
1000 loops, best of 3: 1.03 ms per loop
1000 loops, best of 3: 671 µs per loop

In [412]: n = 100000

In [413]: lst = np.unique(np.random.randint(0,4*n,(n))).tolist()

In [414]: %timeit org_app(lst)
     ...: %timeit np.unique(np.asarray(lst)[:,None] + np.arange(4))
     ...: %timeit mask_app(lst, interval_len = 4)
     ...: 
1 loop, best of 3: 350 ms per loop
100 loops, best of 3: 14.7 ms per loop
100 loops, best of 3: 9.73 ms per loop

这两种发布方法的瓶颈似乎在于转换为array,尽管之后似乎得到了很好的回报。只是为了了解最后一个数据集的转换所花费的时间 -

In [415]: %timeit np.array(lst)
100 loops, best of 3: 5.6 ms per loop

【讨论】:

  • 美丽。像魅力一样工作,而且速度也很快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-02
  • 2021-01-02
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 2011-04-30
相关资源
最近更新 更多