1

リスト内の要素をフィルタリングすることを探しています。

たとえば、リストがあるとします。

listA = ['banana', 'apple', 'appleRed', 'melon_01', 'appleGreen', 'Orange', 'melon_03']
listB = ['apple', 'melon']

次に、リストを比較して、listBで始まる要素名のみを含むリストを作成する必要があります。

結果は次のようになります。

listResult = ['apple', 'appleRed', 'melon_01', 'appleGreen', 'melon_03']

これは、2forループとifループ比較を使用して行うことができます。お気に入り、

for item in listA:
    for fruit in listB:
        if item.startswith(fruit):
            listResult.append(item)
            break

ただし、ビッグリストの比較には時間がかかる可能性があるため、この操作に使用できるショートカットはあるのでしょうか。

4

3 に答える 3

6

リスト内包表記とanyジェネレーターを使用します。

[item for item in listA if any(item.startswith(fruit) for fruit in listB)]

または、@ DSMによって正しく提案されているように:

[item for item in listA if item.startswith(tuple(listB))]

これは最初のソリューションよりもはるかに高速で、@ Iguananautによって提案された正規表現ソリューションとほぼ同じ速度です(ただし、よりコンパクトで読みやすくなっています)。

In [1]: %timeit [item for item in listA if any(item.startswith(fruit) for fruit in listB)]
100000 loops, best of 3: 4.31 us per loop

In [2]: %timeit [item for item in listA if item.startswith(tuple(listB))]
1000000 loops, best of 3: 1.56 us per loop

In [3]: %timeit filter(regex.match, listA)
1000000 loops, best of 3: 1.39 us per loop
于 2012-11-27T15:05:20.393 に答える
2

アイテムが比較的少ない場合は、listBかなり効率的に正規表現にすることができます。

import re
regex = re.compile(r'^(?:%s)' % '|'.join(listB))
filter(regex.match, listA)

それが私の頭に浮かんだ最初のことですが、他の人は他のアイデアを持っていると思います.

もちろん、リスト内包表記を使用した他の回答は完全に問題なく合理的です。少しでも速くする方法はないかと思っていました。繰り返しになりますが、このソリューションは一般的なケースでは常に高速であるとは限らないことを強調する必要がありますが、この場合はわずかに高速です。

In [9]: %timeit [item for item in listA if any(item.startswith(fruit) for fruit in listB)]
100000 loops, best of 3: 8.17 us per loop

In [10]: %timeit filter(regex.match, listA)
100000 loops, best of 3: 2.62 us per loop
于 2012-11-27T15:06:17.090 に答える
1
listResult = [ i for i in listA if any( i.startsWith( j ) for j in listB ) ]
于 2012-11-27T15:05:26.683 に答える