web-dev-qa-db-ja.com

Python:タプルの値を変更する

私はpythonが初めてなので、この質問は少し基本的なものかもしれません。次を含むvaluesというタプルがあります。

('275', '54000', '0.0', '5000.0', '0.0')

このタプルの最初の値(つまり、275)を変更したいのですが、タプルは不変であるため、values[0] = 200は機能しません。どうすればこれを達成できますか?

90
Dawood

最初に尋ねる必要があります、なぜあなたはこれをしたいのですか?

しかし、それは可能です:

t = ('275', '54000', '0.0', '5000.0', '0.0')
lst = list(t)
lst[0] = '300'
t = Tuple(lst)

しかし、物事を変更する必要がある場合は、おそらくlistとして保持する方が良いでしょう。

130
Jon Clements

あなたの問題に応じて、スライスは本当にすてきな解決策になります:

>>> b = (1, 2, 3, 4, 5)
>>> b[:2] + (8,9) + b[3:]
(1, 2, 8, 9, 4, 5)
>>> b[:2] + (8,) + b[3:]
(1, 2, 8, 4, 5)

これにより、複数の要素を追加したり、いくつかの要素を置換したりすることができます(特に「近傍」の場合。上記の場合、リストへのキャストがおそらく適切で読みやすいでしょう(スライス表記がはるかに短い場合でも)。

55
Dave Halter

さて、Trufaがすでに示したように、特定のインデックスでTupleの要素を置き換えるには、基本的に2つの方法があります。タプルをリストに変換するか、要素を置き換えて元に戻すか、連結によって新しいタプルを作成します。

In [1]: def replace_at_index1(tup, ix, val):
   ...:     lst = list(tup)
   ...:     lst[ix] = val
   ...:     return Tuple(lst)
   ...:

In [2]: def replace_at_index2(tup, ix, val):
   ...:     return tup[:ix] + (val,) + tup[ix+1:]
   ...:

それで、どちらの方法が良い、つまり速いですか?

短いタプル(Python 3.3で)の場合、連結は実際に高速であることがわかりました!

In [3]: d = Tuple(range(10))

In [4]: %timeit replace_at_index1(d, 5, 99)
1000000 loops, best of 3: 872 ns per loop

In [5]: %timeit replace_at_index2(d, 5, 99)
1000000 loops, best of 3: 642 ns per loop

それでも、より長いタプルを見ると、リスト変換が進むべき方法です。

In [6]: k = Tuple(range(1000))

In [7]: %timeit replace_at_index1(k, 500, 99)
100000 loops, best of 3: 9.08 µs per loop

In [8]: %timeit replace_at_index2(k, 500, 99)
100000 loops, best of 3: 10.1 µs per loop

非常に長いタプルの場合、リスト変換は大幅に改善されます!

In [9]: m = Tuple(range(1000000))

In [10]: %timeit replace_at_index1(m, 500000, 99)
10 loops, best of 3: 26.6 ms per loop

In [11]: %timeit replace_at_index2(m, 500000, 99)
10 loops, best of 3: 35.9 ms per loop

また、連結方法のパフォーマンスは、要素を置き換えるインデックスに依存します。リスト方式の場合、インデックスは無関係です。

In [12]: %timeit replace_at_index1(m, 900000, 99)
10 loops, best of 3: 26.6 ms per loop

In [13]: %timeit replace_at_index2(m, 900000, 99)
10 loops, best of 3: 49.2 ms per loop

つまり、タプルが短い場合は、スライスして連結します。長い場合は、リスト変換を行います!

18
sjakobi

Hunter McMillenがコメントで書いたように、タプルは不変です。これを実現するには、新しいタプルを作成する必要があります。例えば:

>>> tpl = ('275', '54000', '0.0', '5000.0', '0.0')
>>> change_value = 200
>>> tpl = (change_value,) + tpl[1:]
>>> tpl
(200, '54000', '0.0', '5000.0', '0.0')
6
SuperNova

これは、慣用的なPythonを使用した簡単なワンライナーです。

values = ('275', '54000', '0.0', '5000.0', '0.0')
values = ('300', *values[1:])
5
Brian Spiering

技術的にはこれで質問に答えられると思いますが、自宅ではそうしないでください。現時点では、すべての回答には新しいタプルの作成が含まれますが、ctypesを使用してメモリ内のタプルを変更できます。 64ビットシステムでのCPythonのさまざまな実装の詳細に依存して、これを行う1つの方法は次のとおりです。

def modify_Tuple(t, idx, new_value):
    # `id` happens to give the memory address in CPython; you may
    # want to use `ctypes.addressof` instead.
    element_ptr = (ctypes.c_longlong).from_address(id(t) + (3 + idx)*8)
    element_ptr.value = id(new_value)
    # Manually increment the reference count to `new_value` to pretend that
    # this is not a terrible idea.
    ref_count = (ctypes.c_longlong).from_address(id(new_value))
    ref_count.value += 1

t = (10, 20, 30)
modify_Tuple(t, 1, 50)   # t is now (10, 50, 30)
modify_Tuple(t, -1, 50)  # Will probably crash your Python runtime
4
fuglede

これが優れているというわけではありませんが、誰かが興味を持っている場合は、次のようにして1行で実行できます。

Tuple = Tuple([200 if i == 0 else _ for i, _ in enumerate(Tuple)])
4
bphi

最初に、Tupleを変更する理由を自問してください。Ptyhonでは文字列とタプルが不変である理由があります。Tupleを変更したい場合は、おそらくlistである必要があります。

2番目に、まだタプルを変更したい場合は、Tuplelistに変換してから変換し直し、新しいタプルを同じ変数に再割り当てできます。これは素晴らしいですタプルを1回だけ変更する場合。そうでなければ、個人的には直感に反すると思います。本質的に新しいタプルを作成しているため、タプルを変更する場合は毎回変換を実行する必要があります。また、コードを読んだ場合、単にlistを作成しないのはなぜかと考えると混乱しますか?しかし、ライブラリを必要としないため、素晴らしいです。

mutabletuple 0.2 からmutabletuple(typename, field_names, default=MtNoDefault)を使用することをお勧めします。個人的には、この方法はmore直感的およびreadable.であると思います。このタプルを将来的に変更するために。上記のlist変換メソッドと比較した場合の欠点は、追加のpyファイルをインポートする必要があることです。

from mutabletuple import mutabletuple

myTuple = mutabletuple('myTuple', 'v w x y z')
p = myTuple('275', '54000', '0.0', '5000.0', '0.0')
print(p.v) #print 275
p.v = '200' #mutate myTuple
print(p.v) #print 200

TL; DRTupleを変更しようとしないでください。一度だけの操作である場合は、Tupleをリストに変換し、変更し、listを新しいTupleに変換し、古いTupleを保持している変数に再割り当てします。 Tupleが必要で、何らかの理由でlistを避けたい場合、および複数回変更したい場合は、mutabletupleを作成します。

2
OLIVER.KOO

Jon のアイデアと親愛なる Trufa に基づく

def modifyTuple(tup, oldval, newval):
    lst=list(tup)
    for i in range(tup.count(oldval)):
        index = lst.index(oldval)
        lst[index]=newval

    return Tuple(lst)

print modTupByIndex((1, 1, 3), 1, "a")

古い値の出現をすべて変更します

2
Pooya

編集:これはまだ重複エントリを持つタプルでは動作しません!

Pooyaのアイデア に基づく:

これを頻繁に行うことを計画している場合(タプルは理由により不変なので、そうすべきではありません)、次のようなことをする必要があります。

def modTupByIndex(tup, index, ins):
    return Tuple(tup[0:index]) + (ins,) + Tuple(tup[index+1:])

print modTupByIndex((1,2,3),2,"a")

または Jonのアイデア に基づいて:

def modTupByIndex(tup, index, ins):
    lst = list(tup)
    lst[index] = ins
    return Tuple(lst)

print modTupByIndex((1,2,3),1,"a")
2
Trufa

私はゲームに遅れていますが、(最も単純な、リソースにやさしい、最速の方法(状況に応じて)、タプル自体を上書きすることです。これにより、リストと変数を作成する必要がなくなり、1行でアーカイブされます。

new = 24
t = (1, 2, 3)
t = (t[0],t[1],new)

>>> (1, 2, 24)

しかし、これはかなり小さなタプルにのみ便利であり、固定タプル値に制限されますが、とにかくほとんどの場合タプルに当てはまります。

したがって、この特定のケースでは次のようになります。

new = '200'
t = ('275', '54000', '0.0', '5000.0', '0.0')
t = (new, t[1], t[2], t[3], t[4])

>>> ('200', '54000', '0.0', '5000.0', '0.0')
0
GordanTrevis

できません。変更したい場合は、タプルの代わりにリストを使用する必要があります。

代わりに、新しい値を最初の要素として持つ新しいTupleを作成できることに注意してください。

0
BrenBarn

タプルを編集する最良の方法は、以前のバージョンをベースとしてタプルを再作成することです。

これは、明るいバージョンの色を作成するために使用した例です(その時点で既に開いていました)。

colour = Tuple([c+50 for c in colour])

それが行うことは、タプルの「色」を通過し、各項目を読み取り、それに何かを実行し、最終的に新しいタプルに追加することです。

したがって、あなたが望むのは次のようなものです:

values = ('275', '54000', '0.0', '5000.0', '0.0')

values  = (Tuple(for i in values: if i = 0: i = 200 else i = values[i])

その特定のものは機能しませんが、コンセプトはあなたが必要とするものです。

Tuple = (0, 1, 2)

タプル=タプルを反復処理し、必要に応じて各項目を変更します

それがコンセプトです。

0
Aedus