2016-09-06 3 views
-1

配列の関数を作成しようとしています。配列が入り、値が0の場合はリストの後ろに置かれます。私の関数はほとんどの場合動作しますが、唯一の問題はブール値Falseが0として解釈され続けることです。私は0とFalseを区別するためにAND文を作成しましたが、機能しません。なぜ。リストの理解にANDステートメントを使用できませんか?Pythonリストの理解にANDステートメントを含める

def move_zeros(array): 
    [array.insert(len(array), array.pop(array.index(x))) for x in array if x == 0 and x is not False] 
    return array 

私は2つの例を追加しました.1つの作品。もう1つは私が達成したいことではありません。

入力:[1、 "A"、2、0、3、 "B"]出力:[1、 "A"、2、3、 "B"、0]これは

入力の動作: [1、False、2、0、3、 "b"]出力:[1,2,3、 "b"、False、0] Falseがリストの最後に移動しているので、これは機能しません私はそれを渡したい。

+0

例を使って機能が何をしているのか詳しく教えてください。 Btw、insertは値を返さないため、 'None'の配列を作成しています。また、 'array.insert(len(array)、...)'は 'array.append(...)'と同じです。 – ozgur

+3

リスト内包表記を使用する方法を学ぶ必要があります。それは彼らがどのように使われているかではありません。経験則の簡単なルール:リストの理解に副作用がある場合、それは間違っています。 – spectras

+0

問題を与える 'array'の例を追加します。そして、あなたが望む結果。あなたはリストの理解を '返す 'べきであり、理解の中で変更されるリストはありません。 – hpaulj

答えて

1

あなたのリスト内包にループ代わります。それでもリストは変更されます。他の人が述べたようにx is 00Falseの区別を単純化:このような副作用を

In [106]: al=[0, 1, 2, False, True, 3,0,10] 
In [107]: for i,x in enumerate(al): 
    ...:  if x is 0: 
    ...:   value = al.pop(i) 
    ...:   al.append(value) 
    ...:   
In [108]: al 
Out[108]: [1, 2, False, True, 3, 10, 0, 0] 

は、ループが理解よりも優れています。理解は、次の項目で使用する必要があります。

return [.... for x in al if ...] 

センス。理解の中で列挙を使用することもできます。

return [fun(x, i) for i, x in enumerate(al) if x...] 

明確なリストの理解では、リストは1回だけ表示されます。テストと戻り値は、元のリストではなく、反復変数のみに依存します。

===================

0Falseはしばしば同じように扱われることに注意してください。たとえば、数値を期待する演算では、False0Trueを1と扱います。ブール値を期待する関数は、0Falseとして扱います。リスト内包でand

In [117]: [x+1 for x in al] 
Out[117]: [1, 2, 3, 1, 2, 4, 1, 11] 
In [118]: al=[0, 1, 2, False, True, 3,0,10] 
In [119]: sum(al) 
Out[119]: 17 

=================

例:

In [137]: [x for x in al if x==0] 
Out[137]: [0, False, 0] 
In [138]: [x for x in al if x==0 and x is not False] 
Out[138]: [0, 0] 
In [140]: [x for x in al if not (x==0 and x is not False)] 
Out[140]: [1, 2, False, True, 3, 10] 

======== ====

別の可能な試験 - STR表現の:

In [143]: [x for x in al if str(x)!='0'] 
Out[143]: [1, 2, False, True, 3, 10] 

===============

問題はテストではなく、al.index(x)です。 0Falseの両方に一致しており、どちらがxであるかにかかわらず、最初のテストを削除します。

al.index(x)

バージョン:

def move_zeros(array): 
    [array.insert(len(array), array.pop(i)) for i,x in enumerate(array) if (x == 0 and x is not False)] 
    return array 

In [403]: al=[1,False,2, 0,3,"b"] 
In [404]: move_zeros(al) 
Out[404]: [1, False, 2, 3, 'b', 0] 

孤立してindexをテスト:列挙i

In [399]: al=[1,False,2, 0,3,"b"] 
In [400]: for i,x in enumerate(al): 
    ...:  if x ==0 and x is not False: 
    ...:   al.append(al.pop(i)) 
    ...:   
In [401]: al 
Out[401]: [1, False, 2, 3, 'b', 0] 

またはあなたの関数で

In [396]: al=[1,False,2, 0,3,"b"] 
In [397]: for x in al: 
    ...:  if x ==0 and x is not False: 
    ...:   al.append(al.pop(al.index(x))) 
    ...:   
In [398]: al 
Out[398]: [1, 2, 0, 3, 'b', False] 

バージョン

In [405]: al=[1,False,2, 0,3,"b"] 
In [406]: al.index(0) 
Out[406]: 1 
In [407]: al.index(False) 
Out[407]: 1 
+0

'xが0です.'は実装依存です。 'x = 0 'のために' xが0であるという保証はありません。 – chepner

+0

はい、 'cpython'(主なもの)では、256より小さい整数はユニークで、' is'が動作します。 'pypy'ではそうではないかもしれません(私はその違いを回避するバグ/問題を思い出します)。 – hpaulj

+0

「0」と「False」の両方を含んでいて、扱いが異なると思われるリストは何らかの問題を抱えていると主張できます。 – hpaulj

0

リストをフィルタリングするときに0Falseの意味を区別しようとするのは悪い考えですが、あなたの状況に適した方法がいくつかあります。

はCPythonで動作幾分ハックアプローチはisなく==を使用することである。

def move_zeros(array): 
    zeros = 0 
    new_array = [] 
    for x in array: 
     if not x is 0: 
      new_array.append(x) 
     else: 
      zeros += 1 
    return new_array + [0]*zeros 

@chepnerが指摘するように、これは実装依存です。 Pythonの3で動作し、より堅牢なアプローチがisinstance()を使用することです:

def move_zeros(array): 
    zeros = 0 
    new_array = [] 
    for x in array: 
     if x != 0 or isinstance(x,bool): 
      new_array.append(x) 
     else: 
      zeros += 1 
    return new_array + [0]*zeros 

のいずれかの定義を使用する:

>>> move_zeros([1, False, 2, 0, 3, "b"]) 
[1, False, 2, 3, 'b', 0] 
+0

これは実装依存です。 – chepner

関連する問題