リスト内の要素の検索と置換


273

リストを検索して、ある要素のすべての出現箇所を別の要素で置き換える必要があります。これまでのところ、コードでの試みはどこにも行きませんでした。これを行うための最良の方法は何ですか?

たとえば、私のリストに次の整数があるとします

>>> a = [1,2,3,4,5,1,2,3,4,5,1]

そして、私は数値1のすべての出現を値10に置き換える必要があるので、必要な出力は

>>> a = [10, 2, 3, 4, 5, 10, 2, 3, 4, 5, 10]

したがって、私の目標は、数値1のすべてのインスタンスを数値10に置き換えることです。


11
ところで、これは何のためですか?
outis

回答:


250
>>> a= [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1]
>>> for n, i in enumerate(a):
...   if i == 1:
...      a[n] = 10
...
>>> a
[10, 2, 3, 4, 5, 10, 2, 3, 4, 5, 10]

15
これは良くない、非常に非Pythonicなソリューションです。リスト内包表記の使用を検討してください。
AdHominem 2016

204
これは非常に非Pythonの解決策である場合は問題ありません。リスト内包表記の使用を検討してください。
ジャン=フランソワ・コルベット

以下の@outisによって行われるようなリスト内包表記の使用を検討してください!
amc

6
これはリスト内包よりも優れていますが、そうではありませんか?新しいリストを生成する代わりに、インプレース更新を行います。
neverendingqs

@neverendingqs:いいえ。インタプリタのオーバーヘッドが操作を支配し、理解度はそれよりも少なくなります。理解度は、特に置換条件を通過する要素の割合が高い場合に、わずかに向上します。いくつかのタイミングがあります:ideone.com/ZrCy6z
user2357112は

519

リスト内包表記三項演算子を使用してみてください。

>>> a=[1,2,3,1,3,2,1,1]
>>> [4 if x==1 else x for x in a]
[4, 2, 3, 4, 3, 2, 4, 4]

9
でもこれは変わらないaけどね?OPはa変更したかったと思います
Dula

10
@Dulaあなたはa = [4 if x == 1 else x for a in a]を実行できます。これはaに影響します
Alekhya Vemavarapu

@Dula:a変異する必要があるかどうかはあいまいですが、(Alekhyaが示すように)リスト内包表記を使用する場合、どちらの場合も処理するのは簡単です。
outis

34
変更したい場合はa、変更する必要がありますa[:] = [4 if x==1 else x for x in a](完全なリストスライスに注意してください)。を実行するだけで、元のa =リストaとは異なるid()(アイデンティティ)新しいリストが作成されます
Chris_Rands '25 / 04/25

39

リスト内包表記はうまく機能し、enumerateでループすることでメモリを節約できます(b / c操作は基本的には適切に行われています)。

関数型プログラミングもあります。マップの使用法を参照してください:

>>> a = [1,2,3,2,3,4,3,5,6,6,5,4,5,4,3,4,3,2,1]
>>> map(lambda x: x if x != 4 else 'sss', a)
[1, 2, 3, 2, 3, 'sss', 3, 5, 6, 6, 5, 'sss', 5, 'sss', 3, 'sss', 3, 2, 1]

17
+1。それはあまりにも悪くlambdamap非Pythonic と見なされます。
outis

4
ラムダまたはマップが本質的に非Pythonicであるかどうかはわかりませんが、リストの内包表記は、2つを組み合わせて使用​​するよりも簡潔で読みやすいことに同意します。
damzam 2010

7
私はそれらをunpythonicだと私は考えていませんが、Guido van Rossum(artima.com/weblogs/viewpost.jsp?thread=98196)を含め、多くはunpythonicだと考えています。それはそれらの宗派の一つです。
outis

36

置き換える値が複数ある場合は、辞書を使用することもできます。

a = [1, 2, 3, 4, 1, 5, 3, 2, 6, 1, 1]
dic = {1:10, 2:20, 3:'foo'}

print([dic.get(n, n) for n in a])

> [10, 20, 'foo', 4, 10, 5, 'foo', 20, 6, 10, 10]

1
n見つからない場合、これはエラーをスローしませんdicか?
Neil A.

3
@ user2914540答えが少し改善されたので、n見つからない場合でも機能します。よろしくお願いします。あなたのtry/except解決策は良くありませんでした。
jrjc

ああ、そうです。
roipoussiere

1
@jrjc @roipoussiereインプレース置換の場合、try-except少なくとも50%高速です。この回答を
ご覧ください

4
if n in dic.keys()パフォーマンスに関しては悪いです。使用if n in dicまたはdic.get(n,n)(デフォルト値)
ジャン・フランソワ・ファーブル

12
>>> a=[1,2,3,4,5,1,2,3,4,5,1]
>>> item_to_replace = 1
>>> replacement_value = 6
>>> indices_to_replace = [i for i,x in enumerate(a) if x==item_to_replace]
>>> indices_to_replace
[0, 5, 10]
>>> for i in indices_to_replace:
...     a[i] = replacement_value
... 
>>> a
[6, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6]
>>> 

中速ですが、非常に賢明な方法です。私の回答のタイミングをご覧ください。
仲の良い友達

10
a = [1,2,3,4,5,1,2,3,4,5,1,12]
for i in range (len(a)):
    if a[i]==2:
        a[i]=123

forループまたはwhileループを使用できます。ただし、組み込みのEnumerate関数がわかっている場合は、Enumerateを使用することをお勧めします。1


1
これは、リストアイテムに対してより複雑な操作を実行する必要がある場合に行う唯一の健全な(読み取り可能な)方法です。たとえば、各リストアイテムが長い文字列であり、なんらかの検索と置換が必要な場合です。
not2qubit 2018年

8

簡単にすべて交換する110して a = [1,2,3,4,5,1,2,3,4,5,1]1次1行のラムダ+マップの組み合わせを使用することができなかった、と「ルック、馬、何のIFまたはフォルス!」:

# This substitutes all '1' with '10' in list 'a' and places result in list 'c':

c = list(map(lambda b: b.replace("1","10"), a))


最も遅い方法です。lambdaすべてのリスト要素でa を呼び出しています...
dawg

4

以下はPython 2.xでの非常に直接的な方法です

 a = [1,2,3,4,5,1,2,3,4,5,1]        #Replacing every 1 with 10
 for i in xrange(len(a)):
   if a[i] == 1:
     a[i] = 10  
 print a

この方法は機能します。コメントは大歓迎です。それが役に立てば幸い :)

また、outisdamzamのソリューションがどのように機能するかを理解してください。リスト圧縮とラムダ関数は便利なツールです。


4

長いリストとまれな発生list.index()では、他の回答で提示されたシングルステップの反復方法と比較して、約3倍速く使用できます。

def list_replace(lst, old=1, new=10):
    """replace list elements (inplace)"""
    i = -1
    try:
        while 1:
            i = lst.index(old, i + 1)
            lst[i] = new
    except ValueError:
        pass

これは私が見つけた最速の方法です。私の回答のタイミングをご覧ください。すごい!
仲の良い友達

3

これは非常に古い質問であり、無数の方法があります。私が見つけたより簡単なものはnumpyパッケージを使用することです。

import numpy

arr = numpy.asarray([1, 6, 1, 9, 8])
arr[ arr == 8 ] = 0 # change all occurrences of 8 by 0
print(arr)

3

私のユースケースはNone、いくつかのデフォルト値で置き換えていました。

ここで提示されたこの問題へのアプローチには、@ kxr-usingによるものを含め、時間を設定しましたstr.count

Python 3.8.1でipythonのコードをテストします。

def rep1(lst, replacer = 0):
    ''' List comprehension, new list '''

    return [item if item is not None else replacer for item in lst]


def rep2(lst, replacer = 0):
    ''' List comprehension, in-place '''    
    lst[:] =  [item if item is not None else replacer for item in lst]

    return lst


def rep3(lst, replacer = 0):
    ''' enumerate() with comparison - in-place '''
    for idx, item in enumerate(lst):
        if item is None:
            lst[idx] = replacer

    return lst


def rep4(lst, replacer = 0):
    ''' Using str.index + Exception, in-place '''

    idx = -1
    # none_amount = lst.count(None)
    while True:
        try:
            idx = lst.index(None, idx+1)
        except ValueError:
            break
        else:
            lst[idx] = replacer

    return lst


def rep5(lst, replacer = 0):
    ''' Using str.index + str.count, in-place '''

    idx = -1
    for _ in range(lst.count(None)):
        idx = lst.index(None, idx+1)
        lst[idx] = replacer

    return lst


def rep6(lst, replacer = 0):
    ''' Using map, return map iterator '''

    return map(lambda item: item if item is not None else replacer, lst)


def rep7(lst, replacer = 0):
    ''' Using map, return new list '''

    return list(map(lambda item: item if item is not None else replacer, lst))


lst = [5]*10**6
# lst = [None]*10**6

%timeit rep1(lst)    
%timeit rep2(lst)    
%timeit rep3(lst)    
%timeit rep4(lst)    
%timeit rep5(lst)    
%timeit rep6(lst)    
%timeit rep7(lst)    

私は得る:

26.3 ms ± 163 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
29.3 ms ± 206 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
33.8 ms ± 191 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
11.9 ms ± 37.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
11.9 ms ± 60.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
260 ns ± 1.84 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
56.5 ms ± 204 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

内部を使用するstr.indexと、実際には手動による比較よりも高速です。

テスト4の例外が使用するよりも面倒かどうかは知りませんでした str.count、違いはごくわずかです。

map()(テスト6)は実際のリストではなくイテレーターを返すため、テスト7に注意してください。


2

あなたは単純にPythonでリスト内包を使うことができます:

def replace_element(YOUR_LIST, set_to=NEW_VALUE):
    return [i
            if SOME_CONDITION
            else NEW_VALUE
            for i in YOUR_LIST]

あなたの場合、1のすべての出現を10に置き換えたい場合、コードスニペットは次のようになります。

def replace_element(YOUR_LIST, set_to=10):
    return [i
            if i != 1  # keeps all elements not equal to one
            else set_to  # replaces 1 with 10
            for i in YOUR_LIST]

3
このコードスニペットは問題を解決する可能性がありますが、説明を含めると、投稿の品質を向上させるのに役立ちます。あなたは将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。また、コードと説明コメントを混同しないようにしてください。これにより、コードと説明の両方が読みにくくなります。
Filnor

-1

アイテムを1つだけ見つけて置き換える

ur_list = [1,2,1]     # replace the first 1 wiz 11

loc = ur_list.index(1)
ur_list.remove(1)
ur_list.insert(loc, 11)

----------
[11,2,1]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.