【问题标题】:Find indicies of string in list of strings for an unsorted list在未排序列表的字符串列表中查找字符串索引
【发布时间】:2019-04-29 13:40:42
【问题描述】:

问题陈述

如果给你一个字符串,我们就叫它target,你能把target在一些输入字符串列表中的所有索引都给我吗(这很重要,它是一个字符串列表而不是数字) ,我们称之为input_list。示例输入:

target = '1234'
input_list = [str(x) for x in range(30000)] + [str(x) for x in range(30000)]

您不能假设input_list 已排序,如果您想对列表进行排序,您需要将其添加到您自己的benchmarkFind() 版本中。简单的解决方案是执行以下操作,但这可能非常低效:

def benchmarkFind(target,input_list):
    out = []
    for i in range(len(input_list)):
        if input_list[i] == target:
            out.append(i)
    return out

这里的答案是:

idx = [1234, 31234]

基准测试结果

>>> %timeit benchmarkFind(target,input_list)
100 loops, best of 3: 3.07 ms per loop

用户评论结果

来自@trincot 和@Abhinav Sood - 稍微好一点,但不是很好。

def enumerateFind(target,input_list):
    return [i for i, e in enumerate(input_list) if e == target]

>>> %timeit enumerateFind(target,input_list)
100 loops, best of 3: 2.96 ms per loop

来自@B。 M - 这看起来是迄今为止最好的答案

def primitiveFind(target ,input_list):
    try :
        l=[]
        u=-1
        while True:
            u = input_list.index(target,u+1)
            l.append(u)
    except ValueError:
        return l

>>> %timeit primitiveFind(target,input_list)
1000 loops, best of 3: 577 µs per loop

【问题讨论】:

  • 如果您要返回整个列表,那么创建生成器没有任何优势。你试过[i for i, val in enumerate(input_list) if val == target]吗?
  • @trincot 是的。尽管这确实通常更快,而且速度并不快。我已经更新了问题陈述以澄清问题,并提供了一个包含您的建议的示例。
  • 计时结果实际上取决于列表相对于搜索值的稀疏程度。另见this answer and comments。以前有人问过这个问题。

标签: python list performance indexing


【解决方案1】:

众所周知,Python 循环很慢,但 list 上的原始循环很快。 list.index 很快。

def find2(target ,input_list):
    try :
        l=[]
        u=-1
        while True:
        u= input_list.index(target,start=u+1)
        l.append(u)
    except ValueError:
        return l

运行:

In [32]: find2(target,input_list)
Out[32]: [1234, 31234]

In [33]: %timeit find2(target,input_list)
2.8 ms ± 255 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [34]: %timeit benchmarkFind(target,input_list)
12 ms ± 1.35 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [35]: %timeit [i for i, e in enumerate(input_list) if e == target]
14.2 ms ± 1.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

今天早上我的电脑速度快了 4 倍。

编辑

为了进一步调整,数据对齐很重要,numpy 数组是实现这一点的好方法。不幸的是,从列表转换成本很高,所以如果数据可以以数组形式提供,这很有意义:

input_arr=np.array(input_list)

(input_arr==target).nonzero()
(array([ 1234, 31234], dtype=int64),)

%timeit input_arr=np.array(input_list)
10.6 ms ± 414 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit (input_arr==target).nonzero()
1.56 ms ± 123 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

  • 好评论,是的,永远不会偏离原始太远!我在上面提供了您评论的一个工作示例,到目前为止它看起来确实是禁食的方法!请在我的帖子中查看我更新的“用户评论结果”部分。
【解决方案2】:

枚举速度更快:

python -m timeit -s "\
    target = '1234';\
    input_list = [str(x) for x in range(30000)] + [str(x) for x in range(30000)];\
    idx = [i for i, e in enumerate(input_list) if e == target]"

100000000 次循环,3 次中的最佳:0.00582 微秒每个循环

【讨论】:

  • @Abbhinav 我不确定您在哪里看到了这种性能,但这是不对的> 请在我的帖子中查看我更新的“用户评论结果”部分。枚举通常更快,是的,但不会快很多。
  • @walsha2 我在具有 24G 内存的 RHEL Linux 机器上从 Anaconda(使用 GCC 7.2.0)的 Python 3.6.5 上运行它。我又跑了一遍,仍然看到大致相同的时间:100000000 loops, best of 3: 0.00585 usec per loop
  • 仍然不能用类似的机器重新创建这个。那个时候不可能对。另外,那个时间与上面和其他问题中报告的所有内容都不一致。我认为正确的答案仍然是 B.M.已发布。
  • 这太奇怪了,但是看看不同技术之间的比较非常棒。此外,我建议对您正在评估的所有可能的解决方案使用相同数量的迭代。
猜你喜欢
  • 1970-01-01
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-08
  • 2012-05-16
相关资源
最近更新 更多