10

次のように、リストから奇数を削除する関数を作成しました。

def remove_odd(l):
    for i in l:
        if i % 2 != 0:
            l.remove(i)
    print l
    return l

remove_odd([4,5,4])
remove_odd([4,5,4,7,9,11])
remove_odd([4,5,4,7,9,11,12,13])

それは戻ります:

[4, 4]
[4, 4, 9]
[4, 4, 9, 12]

->間違っている

しかし、偶数を削除するように変更すると、次のようになります。

def remove_even(l):
    for i in l:
        if i % 2 == 0:
            l.remove(i)
    print l
    return l

remove_even([4,5,4])
remove_even([4,5,4,7,9,11])
remove_even([4,5,4,7,9,11,12,13])

答えはOKです:

[5]
[5, 7, 9, 11]
[5, 7, 9, 11, 13]

remove_odd()関数の何が問題になっていますか?通常、人々はfunc内に2番目のリストを作成し、そのリストに偶数を追加することを知っていますが、この演習をlist.remove()で解決できますか?

ありがとうございました!

4

9 に答える 9

17

関数は、予想とは異なる方法で機能しています。ループは2番目などではなく、最初の要素を取ります。forしたがって、1つの要素を削除すると、他の要素は位置を変更し、前に別の奇数が付いている場合はスキップできます(この場合はスキップできます)。

メソッドの使用を主張する場合は.remove()、代わりに次のようにコピーを操作する必要があります。

def remove_odd(1):
    for i in l[:]:
        if i % 2 != 0:
            l.remove(i)
    return l

l[:]リストの浅いコピーですl

ただし、リスト内包表記を使用する方がはるかに明確になると思います。

def remove_odd(l):
    return [x for x in l if x % 2 == 0]
于 2013-01-11T09:37:35.737 に答える
6

remove_odd()関数の何が問題になっていますか?

リストのサイズを変更しながら、リストを繰り返し処理しています。これにより、1つ以上の要素がスキップされます

リスト内包表記を使ってみませんか。そのよりPythonic、そして読みやすい

def remove_odd(l):
    return [e for e in l if e % 2 == 0]

remove_odd([4,5,4,7,9,11])
[4, 4]

同様に、remove_evenルーチンを作成できます

def remove_even(l):
    return [e for e in l if e % 2]

remove_even([4,5,4,7,9,11])
[5, 7, 9, 11]
于 2013-01-11T09:32:27.553 に答える
5

Pythonには、このための組み込みメソッドがあります。filter

filtered_list = filter(lambda x: x%2==0, input_list)

Python 3では注意してください。ここでは、フィルターはジェネレーターにすぎないため、次のように記述する必要があります。

filtered_list = list(filter(lambda x: x%2==0, input_list))
于 2013-01-11T09:37:57.233 に答える
3

リストを繰り返し処理しているときに、リストを変更しようとしています。

次のようなものを試してください。

In [28]: def remove_odd(l):
    return [x for x in l if x%2 == 0]
   ....: 

In [29]: remove_odd([4,5,4,7,9,11])
Out[29]: [4, 4]

In [30]: remove_odd([4,5,4,7,9,11,12,13])
Out[30]: [4, 4, 12]

または、コードのみを修正するには、を繰り返す必要がありますl[:]

l[:]lと同等の浅いコピーを返しますlist(l)

In [38]: def remove_odd(l):
        for i in l[:]:
                if i % 2 != 0:
                      l.remove(i)
        return l
   ....:     

In [39]: remove_odd([4,5,4,7,9,11,12,13])
Out[39]: [4, 4, 12]

In [40]: remove_odd([4,5,4,7,9,11])
Out[40]: [4, 4]
于 2013-01-11T09:32:50.313 に答える
2

リスト全体を変更する最良の方法は、そのコピーを使用することです。

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l=range(10)
>>> type(l)
<type 'list'>
>>> l[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> type(l[:])
<type 'list'>
>>>

オフドキュメントから:

ループ内で繰り返し処理するシーケンスを変更する必要がある場合(たとえば、選択したアイテムを複製する場合)、最初にコピーを作成することをお勧めします。シーケンスを反復処理しても、暗黙的にコピーは作成されません。スライス表記はこれを特に便利にします:

   >>>>>> for w in words[:]:  # Loop over a slice copy of the entire list.
    ...     if len(w) > 6:
    ...         words.insert(0, w)
    ...
    >>> words
    ['defenestrate', 'cat', 'window', 'defenestrate']

http://docs.python.org/2/tutorial/controlflow.html

そして特にあなたの例のために:

def remove_odd(l):
    for i in l[:]:
        if i % 2:
            l.remove(i)
    return l

うまく動作します。

于 2013-01-11T09:36:28.680 に答える
1

例で使用すると、何が起こっているのかを理解できenumerateます。

def remove_odd(l):
    for n, i in enumerate(l):
        print n, i
        if i % 2 != 0:
            l.remove(i)
    print l
    return l

remove_odd([4,5,4,7,9,11])

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

0 4
1 5
2 7
3 11
[4, 4, 9]

したがって、最初と2番目のケースでは、forループは正しい値4と5を使用します。ただし、から5を削除しますl。次に、3番目のステップで、3番目の位置の4ではなく7を呼び出します。lしたがって、他の回答ですでに示唆されているように、をコピーするのが最善です。

于 2013-01-11T09:47:29.863 に答える
1

あなたはこのように試すことができます..

def remove_odd(l):
    a=[]
    for i in range(len(l)):
        if(l[i]%2 ==0):
            a.append(l[i])
    return a
print remove_odd([1,2,2,6,4,1,3])
于 2015-08-13T20:57:21.110 に答える
1
import numpy as np
rand_vec3 = np.arange(0,10)
print(rand_vec3)
print(rand_vec3[rand_vec3 % 2 == 0])
于 2021-03-28T04:00:10.717 に答える
0

ここで別の実装とパフォーマンスのテストを行います。実際の目標は、実際のリストを変更せずに、同じリスト内のオッズ数を削除することです。

最初のアプローチ

# --- Naive Approach Brute Force
def remove_odd(array):
    """Very unefficient Funciton, it has to copy the arr then iterate through it, then calls
    remove function, however it does the job, good for small Lists"""
    array_copy = array.copy()
    for n in array_copy:
        if n % 2 != 0:
            array.remove(n)
    return array

tests = [[4,5,4], [4,5,4,7,9,11], [4,5,4,7,9,11,12,13]]
for test in tests:
    print(f'List Before --> {test}')
    result = remove_odd(test)
    print(f'List After --> {test}')
    print('===='*15)

## Other Solution ##

def remove_odd(array):
    """Better Solution, it iterates through the Array once"""
    idx = 0
    offset = 0  # NOTE: Offset keeps tracks of the jumps after each iteration
    max_iter = len(array)
    while max_iter:
        n = array[idx-offset]

        if n % 2 != 0:
            offset += 1
            array.remove(n)

        idx += 1
        max_iter -= 1

tests = [[4,5,4], [4,5,4,7,9,11], [4,5,4,7,9,11,12,13]]
for test in tests:
    print(f'List Before --> {test}')
    result = remove_odd(test)
    print(f'List After --> {test}')
    print('===='*15)

両方の関数を出力します##

List Before --> [4, 5, 4]
List After --> [4, 4]
============================================================
List Before --> [4, 5, 4, 7, 9, 11]
List After --> [4, 4]
============================================================
List Before --> [4, 5, 4, 7, 9, 11, 12, 13]
List After --> [4, 4, 12]
============================================================

ベンチマーク

于 2021-01-20T18:44:13.407 に答える