12

文字列にリストの項目の文字が含まれているかどうかを確認する最も速い方法は何ですか?

現在、私はこの方法を使用しています:

lestring = "Text123"

lelist = ["Text", "foo", "bar"]

for x in lelist:
    if lestring.count(x):
        print 'Yep. "%s" contains characters from "%s" item.' % (lestring, x)

反復せずにそれを行う方法はありますか (これにより、より高速になると思います)?

4

4 に答える 4

22

メンバーシップチェックでリストの理解を試すことができます

>>> lestring = "Text123"
>>> lelist = ["Text", "foo", "bar"]
>>> [e for e in lelist if e in lestring]
['Text']

あなたの実装と比較して、LCには暗黙的なループがありますが、あなたの場合のように明示的な関数呼び出しがないため、より高速ですcount

Joe の実装と比較すると、フィルター関数はループ内で 2 つの関数を呼び出す必要があるため、あなたの実装ははるかに高速ですlambdacount

>>> def joe(lelist, lestring):
    return ''.join(random.sample(x + 'b'*len(x), len(x)))

>>> def uz(lelist, lestring):
    for x in lelist:
        if lestring.count(x):
            return 'Yep. "%s" contains characters from "%s" item.' % (lestring, x)


>>> def ab(lelist, lestring):
    return [e for e in lelist if e in lestring]

>>> t_ab = timeit.Timer("ab(lelist, lestring)", setup="from __main__ import lelist, lestring, ab")
>>> t_uz = timeit.Timer("uz(lelist, lestring)", setup="from __main__ import lelist, lestring, uz")
>>> t_joe = timeit.Timer("joe(lelist, lestring)", setup="from __main__ import lelist, lestring, joe")
>>> t_ab.timeit(100000)
0.09391469893125759
>>> t_uz.timeit(100000)
0.1528471407273173
>>> t_joe.timeit(100000)
1.4272649857800843

Jamie のコメント付きソリューションは、文字列が短いほど遅くなります。テスト結果はこちら

>>> def jamie(lelist, lestring):
    return next(itertools.chain((e for e in lelist if e in lestring), (None,))) is not None

>>> t_jamie = timeit.Timer("jamie(lelist, lestring)", setup="from __main__ import lelist, lestring, jamie")
>>> t_jamie.timeit(100000)
0.22237164127909637

短い文字列のブール値が必要な場合は、上記の LC 式を変更するだけです

[e in lestring for e in lelist if e in lestring]

または、より長い文字列の場合、次のことができます

>>> next(e in lestring for e in lelist if e in lestring)
True

また

>>> any(e in lestring for e in lelist)
于 2013-01-19T06:08:58.030 に答える
1
filter(lambda x: lestring.count(x), lelist)

これにより、検索しようとしているすべての文字列がリストとして返されます。

于 2013-01-19T06:08:24.120 に答える
0

テストが共通の文字 (単語やセグメントではない) があるかどうかを確認することである場合は、リスト内の文字からセットを作成し、文字列を文字列と照合します。

char_list = set(''.join(list_of_words))
test_set = set(string_to_teat)
common_chars = char_list.intersection(test_set)

ただし、共通のキャラクターを 1 つだけ探していると仮定しています...

于 2013-01-19T06:20:15.930 に答える
0

esmreライブラリがそのトリックを行います。あなたの場合、より単純なesm (esmre の一部) が必要です。

https://pypi.python.org/pypi/esmre/

https://code.google.com/p/esmre/

彼らは良いドキュメントと例を持っています: 彼らの例から取られた:

>>> import esm
>>> index = esm.Index()
>>> index.enter("he")
>>> index.enter("she")
>>> index.enter("his")
>>> index.enter("hers")
>>> index.fix()
>>> index.query("this here is history")
[((1, 4), 'his'), ((5, 7), 'he'), ((13, 16), 'his')]
>>> index.query("Those are his sheep!")
[((10, 13), 'his'), ((14, 17), 'she'), ((15, 17), 'he')]
>>> 

いくつかのパフォーマンス テストを実行しました。

import random, timeit, string, esm

def uz(lelist, lestring):
    for x in lelist:
        if lestring.count(x):
            return 'Yep. "%s" contains characters from "%s" item.' % (lestring, x)



def ab(lelist, lestring):
    return [e for e in lelist if e in lestring]


def use_esm(index, lestring):
    return index.query(lestring)

for TEXT_LEN in [5, 50, 1000]:
    for SEARCH_LEN in [5, 20]:
        for N in [5, 50, 1000, 10000]:
            if TEXT_LEN < SEARCH_LEN:
                continue

            print 'TEXT_LEN:', TEXT_LEN, 'SEARCH_LEN:', SEARCH_LEN, 'N:', N

            lestring = ''.join((random.choice(string.ascii_uppercase + string.digits) for _ in range(TEXT_LEN)))
            lelist = [''.join((random.choice(string.ascii_uppercase + string.digits) for _ in range(SEARCH_LEN))) for _
                      in range(N)]

            index = esm.Index()
            for i in lelist:
                index.enter(i)
            index.fix()

            t_ab = timeit.Timer("ab(lelist, lestring)", setup="from __main__ import lelist, lestring, ab")
            t_uz = timeit.Timer("uz(lelist, lestring)", setup="from __main__ import lelist, lestring, uz")
            t_esm = timeit.Timer("use_esm(index, lestring)", setup="from __main__ import index, lestring, use_esm")

            ab_time = t_ab.timeit(1000)
            uz_time = t_uz.timeit(1000)
            esm_time = t_esm.timeit(1000)

            min_time = min(ab_time, uz_time, esm_time)
            print '  ab%s: %f' % ('*' if ab_time == min_time else '', ab_time)
            print '  uz%s: %f' % ('*' if uz_time == min_time else '', uz_time)
            print '  esm%s %f:' % ('*' if esm_time == min_time else '', esm_time)

結果は、探しているアイテムの数 (私の場合は「N」) に大きく依存することがわかりました。

TEXT_LEN: 1000 SEARCH_LEN: 20 N: 5
  ab*: 0.001733
  uz: 0.002512
  esm 0.126853:

TEXT_LEN: 1000 SEARCH_LEN: 20 N: 50
  ab*: 0.017564
  uz: 0.023701
  esm 0.079925:

TEXT_LEN: 1000 SEARCH_LEN: 20 N: 1000
  ab: 0.370371
  uz: 0.489523
  esm* 0.133783:

TEXT_LEN: 1000 SEARCH_LEN: 20 N: 10000
  ab: 3.678790
  uz: 4.883575
  esm* 0.259605:
于 2014-05-12T10:32:43.033 に答える