Python在列表或数组中查找范围之间的数字

Posted

技术标签:

【中文标题】Python在列表或数组中查找范围之间的数字【英文标题】:Python find numbers between range in list or array 【发布时间】:2018-04-09 08:26:53 【问题描述】:

我有一个包含数百万个数字的列表,这些数字总是增加到最后,我需要在指定范围内查找并返回数字,例如大于 X 但小于 Y 的数字,列表中的数字可以更改,我正在搜索的值也会更改

我一直在使用这种方法,请注意这是一个基本示例,数字不统一或与我的程序中显示的相同

l = [i for i in range(2000000)]
nums = []
for element in l:
    if element > 950004:
        break
    if element > 950000:
        nums.append(element)
#[950001, 950002, 950003, 950004]

虽然速度很快,但对于我的程序正在执行的操作,我有点需要它更快一点,数字变化很大,所以我想知道是否有更好的方法来使用 pandas 系列或 numpy 数组来做到这一点?但到目前为止,我所做的只是在 numpy 中做了一个示例:

a = numpy.array(l,dtype=numpy.int64)

熊猫系列会更实用吗?使用查询()?使用数组而不是 python 对象的 python 列表来解决这个问题的最佳方法是什么

【问题讨论】:

您是否尝试将列表过滤为一组值之间的数字? 不,抱歉,返回 x 和 y 之间的值 您似乎只是想从950000950004 中提取一个切片。有什么意义? 也许,用二分法搜索范围边界的索引会更快。 您能否更新您的示例以更接近您的实际问题? 【参考方案1】:

这是一个使用二分搜索的解决方案。你说的是数以百万计的数字。从技术上讲,二分搜索将通过将运行时复杂度降低到 O(log n) 来使算法更快,而忽略最后的切片步骤。

import bisect

l = [i for i in range(2000000)]
lower_bound = 950000
upper_bound = 950004

lower_bound_i = bisect.bisect_left(l, lower_bound)
upper_bound_i = bisect.bisect_right(l, upper_bound, lo=lower_bound_i)
nums = l[lower_bound_i:upper_bound_i]

【讨论】:

不知何故它比 numpy 布尔切片 O_o 快一点; 谢谢,我可能在浏览文档时找不到这个解决方案 bisect.bisect_right 中使用lo=lower_bound_i 参数可以提高效率。 @new_to_coding 这个列表切片,你的意思是?是的,一个布尔切片创建一个与当前数组大小相同的整个布尔数组。 Python list-slice 非常快速和高效,用 C 实现。【参考方案2】:

以下是二分查找的两种实现(基于来自here 的代码)——一种搜索上限,另一种搜索下限。这对你更有效吗?

def binary_search_upper(seq, limit):
    min = 0
    max = len(seq) - 1
    while True:
        if max < min:
            return -1
        m = (min + max) / 2
        if m == (len(seq) -1) or (seq[m] <= limit and seq[m+1] > limit):
            return m
        elif seq[m] < limit:
            min = m+1
        else:
            max = m - 1

def binary_search_lower(seq, limit):
    min = 0
    max = len(seq) - 1
    while True:
        if max < min:
            return -1
        m = (min + max) / 2
        if m == 0 or (seq[m] >= limit and seq[m-1] < limit):
            return m
        elif seq[m] < limit:
            min = m+1
        else:
            max = m - 1


l = [i for i in range(2000000)]
print binary_search_upper(l, 950004)
print binary_search_lower(l, 950000)

【讨论】:

你为什么要使用这个已有 14 年历史的配方,而不是标准库实现(它将有很多、很多更好的常数因子)?跨度> JFTR,这比bisect慢十倍左右。 @ekhumoro 很有趣,我在哪里可以了解更多关于 bisect 为何如此之快的信息? @MaorVeitsman。 source code for the module 显示的是纯 python 实现,但 real implementation 是用 C 编写的。 @MaorVeitsman。 PS:纯python bisect 实现的速度大约是你的两倍:P【参考方案3】:

您可以使用 numpy 通过布尔切片获取列表的子集。

import numpy as np
a = np.arange(2000000)
nums = a[(950000<a) & (a<=950004)]
nums
# returns
array([950001, 950002, 950003, 950004])

【讨论】:

我的程序中的数字不一样,这是一个基本的例子,对不起 这个取整个数组中的所有数字,碰到停止条件后不退出。

以上是关于Python在列表或数组中查找范围之间的数字的主要内容,如果未能解决你的问题,请参考以下文章

查找列表中连续数字之间的差异(Python)

在数字列表中查找下一个奇数或下一个偶数

Python - 在数字列表中查找最大数字

SQL解析值列表以查找大于/小于/范围

Python - 在混合数组(整数,列表)中查找每次出现的值

怎么查找python列表中元素的位置