Pythonを学習しようとしたときに、この問題に遭遇しました。次の機能を検討してください。
def swap0(s1, s2):
assert type(s1) == list and type(s2) == list
tmp = s1[:]
s1 = s2[:]
s2 = tmp
return
s1 = [1]
s2 = [2]
swap0(s1, s2)
print s1, s2
S1とs2は何を印刷しますか?
問題を実行した後、printステートメントが1 2を出力することがわかりました。s1とs2の値はswap0
関数から変更されていないようです。私が考えることができた唯一の説明は、線のためでした。
tmp = s1[:]
S1 [:]はコピーであるため、これはs1の値が関数呼び出しで変更されないことを意味します。ただし、swap0
のパラメーターは(s1、s2)なので、tmp = s1 [:]を実行した後かどうかはわかりません。いつでも
s1 = something...
s1自体ではなく、s1のコピーへの参照になります。誰かがより良い説明を提供できますか?ありがとう。
これは、s1
関数内のs2
およびswap0
に新しい値を割り当てるためです。これらの割り当ては、関数の外部には伝播しません。関数呼び出しの代わりに関数本体をコピーして貼り付けるだけで機能することがわかります。
引数自体ではなく、引数によって参照されるオブジェクトを変更することにより、この問題を回避できます。
def swap0(s1, s2):
assert type(s1) == list and type(s2) == list
tmp = s1[:]
s1[:] = s2
s2[:] = tmp
ただし、Pythonでスワップを行うより簡単でより良い方法は単純です:
s1, s2 = s2, s1
これも、リストへの特定の参照のみを交換し、リストの内容自体は交換しません。
そのまま、最終的なprint
はs1
およびs2
の元の値を出力します。これは、関数のスコープ内でのみスワップしているためです。そうしても、関数の外部の値には影響しません(つまり、関数が呼び出された後の値の後)
それらが可変タイプ(list
、set
、dict
など)である場合、swap
内でインプレースで変更できます。ただし、それはswap
が可変型でのみ機能するように制限します。
したがって、入力を逆の順序で返すほうがよいでしょう。
def swap(s1, s2):
return s2, s1
s1 = 'a'
s2 = 'b'
s1, s2 = swap(s1, s2)
print s1, s2 # prints 'b a'
もちろん、次のようにすべてを1行で実行できます。
s1, s2 = s2, s1
乾杯!
他の答えは何が悪いのかを説明しています。これはあなたが望むことをするバージョンです:
def swap(s1, s2):
assert isinstance(s1, list) and isinstance(s2, list)
s1[:], s2[:] = s2[:], s1[:]
関数内で、local variables s1
およびs2
右側に値があります(コピーを作成するためにスライスを使用しているため、これもローカルです)。これらのローカル変数の内容を変更しても、同じリストを参照しなくなるため、呼び出しスコープのリストの内容は変更されません。
目標を達成する1行の関数を次に示します。
swap = lambda x: (x[1], x[0])
また、両方のリストの長さが同じ場合、インデックスとループを使用する古いスワッピング方法でこれを行うこともできます。これは一種の古い学校ですが、インデックス作成の理解に役立ちます
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
b = [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
for i in range(0, len(a)):
a[i] = a[i] + b[i]
b[i] = a[i] - b[i]
a[i] = a[i] - b[i]
print(a)
print(b)
これにより、出力が次のようになります。
[0,9,8,7,6,5,4,3,2,1]
[1,2,3,4,5,6,7,8,9,0]
または、Xorを使用して行うこともできます。 Xor演算子は、たとえばオペランド間でXor演算を行うビット単位の演算子です。
a = 5 #0b101
b = 4 #0b100
c = a ^ b #0b001
ここで、0b101
は5のバイナリ表現であり、0b100
は4のバイナリ表現であり、これらをXorすると、出力は0b001
すなわち1になります。 Xorは、入力が1つで1つだけの場合、1つの出力結果を返します。両方の入力が0であるか、両方が1である場合、出力結果は0です。たとえば、Xorを使用して2つの変数を交換できます。
a = 5 # 0b0101
b = 9 # 0b1001
a = a ^ b # Xor (0b0101, 0b1001) = 0b1100 (12)
b = a ^ b # Xor (0b1100, 0b1001) = 0b0101 (5)
a = a ^ b # Xor (0b1100, 0b0101) = 0b1001 (9)
print("a = {} and b = {}".format(a, b))
出力はa = 9 and b = 5
になります
同様に、次の項目に対してXor操作を実行することにより、2つのリストを交換することもできます。
a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ]
b = [ 0, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]
for i in range(0, len(a)) :
a[i] = a[i] ^ b[i]
b[i] = a[i] ^ b[i]
a[i] = a[i] ^ b[i]
print(a)
print(b)
出力:
[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
別のシナリオを考えてみましょう。たとえば、リスト内のアイテムを交換する必要がある場合は、このx = [ 13, 3, 7, 5, 11, 1 ]
のようなリストがあり、このアイテムをx = [ 1, 3, 5, 7 , 11, 13 ]
のように交換する必要があります。 2つのビット演算子Xor ^
およびCompliments ~
を使用する
コード:
# List of items
a = [ 13, 3, 7, 5, 11, 1 ]
# Calculated the length of list using len() and
# then calulated the middle index of that list a
half = len(a) // 2
# Loop from 0 to middle index
for i in range(0, half) :
# This is to prevent index 1 and index 4 values to get swap
# because they are in their right place.
if (i+1) % 2 is not 0 :
#Here ~i means the compliment of i and ^ is Xor,
# if i = 0 then ~i will be -1
# As we know -ve values index the list from right to left
# so a [-1] = 1
a[i] = a[i] ^ a[~i]
a[~i] = a[i] ^ a[~i]
a[i] = a[i] ^ a[~i]
print(a)
したがって、出力は[1, 3, 5, 7, 11, 13]
になります
あなたはこれを持つことができます:
def swap(x , y):
x , y = y , x
return x , y
x = 5
y = 10
print ('x is {0} and y is {1}'.format(x,y)) # x is 5 and y is 10
x , y = swap(x,y) # doing swap
print ('x is {0} and y is {1}'.format(x,y)) # x is 10 and y is 5