🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1068閲覧

[Python]あるリストの要素を昇順に並び替えたリストを新規作成したい

yokkesama

総合スコア9

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/10/12 14:58

前提・実現したいこと

[Python]あるリストの要素を昇順に並び替えたリストを新規作成したい
ここに質問の内容を詳しく書いてください。

発生している問題・エラーメッセージ

リストaの要素を昇順に並び替えたリストbを作成すると、元のリストaの要素も昇順になってしまう。

該当のソースコード

Python

1import numpy as np 2a = np.random.randint(0,50,4) 3 4b = a 5 6for i in range(3): 7 for j in range(i+1,4): 8 if b[i] > b[j]: 9 p = b[i] 10 q = b[j] 11 b[i] = q 12 b[j] = p 13 14print('a =',a) 15print('b =',b) 16 17

試したこと

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

バブルソートを実装してみる、という主旨でしょうか。

python

1a = np.random.randint(0,50,4)

こうするとリストではなくnumpy配列型の返り値が得られます。その相違は問題にしない、というのであればこれでも構いませんが。

python

1b = a

pythonの変数は単なるオブジェクトへの参照なので、この代入はbaと同じものを参照するようにする、以上の意義はありません。

コピーして別のものを作るといいでしょう。幸いnumpy配列にはcopyメソッドがありますから、7文字の追加で目的を達成できます(listにもあるので、そっちでやるにしてもやることは変わらないけど)。

python

1b = a.copy()

投稿2019/10/12 15:08

hayataka2049

総合スコア30935

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ndarrayの浅いコピーを取って下さい。

Python

1b = a.copy()

投稿2019/10/12 15:03

編集2019/10/12 15:05
LouiS0616

総合スコア35668

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2019/10/12 15:12

これ、shallow copyと言って良いんでしょうか……(object型のときは参照が入るからshallowには間違いないけど、それ以外のときはdeep copyとして扱って差し支えない、みたいな面倒臭いことになってるはず)
LouiS0616

2019/10/12 15:14

参照先がたまたまイミュータブルなだけで、シャローコピーであることに違いは無いと認識しています。
hayataka2049

2019/10/12 15:18

たまたま値型、ということではなくてですか? (参照型/値型の区別なく配列の実体がそのままcopyされるものだと認識しているのですが)
LouiS0616

2019/10/12 15:24 編集

C実装にまで立ち入るのならともかく、Pythonの言語レベルに値型ってありましたっけ? 数値も参照ですよね。
hayataka2049

2019/10/12 15:43

C実装の話です。今回のようなケースでは値型配列がまるごとコピーされる、参照型のnumpy配列では参照値の配列がコピーされる、という動作になり、shallow, deepどちらとも言い難いという主張です。 煩雑なのでpythonレイヤで見ようというスタンスは理解しているつもりですが、「pythonレイヤではshallow copyとみなせる」という主張には違和感を覚えます。
LouiS0616

2019/10/12 16:10 編集

Cレイヤなら、逆に参照型なんて存在しない、という話になってしまうのでは? C界隈で deep copy って言い回しはあまり聞かない印象なのですが。構造体のメンバであろうと配列の要素であろうと常にフルコピーされるのが前提の言語ですよね。
LouiS0616

2019/10/12 16:09

PyObjectポインタ(値型)がやり取りされるだけですので。Cから見れば。
hayataka2049

2019/10/12 16:17

その点に関してはごもっともです…… なので、Cレイヤ的な見方で言うならただの値型のコピー、縮めてただのコピーで良いかと思います。
LouiS0616

2019/10/12 16:40 編集

a = [1], b = [2] のとき、 lst2d = [a, b] のシャローコピーは [a, b] であり、ディープコピーは [a[:], b[:]] である。このことは誰もが同意することかと思います。 では aa = [a, a], bb = [b, b] のとき、 lst3d = [aa, bb] のシャローコピーは何でしょうか。ディープコピーはおそらく [[a[:], a[:]], [b[:], b[:]]] だと思いますが。 全てが参照であるPythonについては、個人的にはむしろ一般のコピーはシャロ―コピーであって、**明示的に**イミュータブルな要素まで掘り下げてコピーすることがディープコピーなのだと考えています。階層の深さは気にしていません。 ただこれは独自研究もいいとこなので、もし明確な定義付けがあるのでしたら教えて下さい。 --- ただ前述の定義に基けば arr2 = arr1 もシャロ―コピーになっちゃうのですよね。ちょっとこの辺りは私自身突き詰めきれてないような自覚もあります。 一階層以上の掘り下げは必要、というルールも設けているのかもしれません。
hayataka2049

2019/10/12 17:25

その見方には大部分に同意できません。 まず枝葉から。 >ディープコピーは [a[:], b[:]] である。 lst2d[0][0] is copy.deepcopy(lst2d[0][0]) # => True は個人的には極めて不服です。原則に反した結果と捉えます。実際にはこうなりますが。 オブジェクトがimmutableかどうか判定する手段はありませんから、おそらく**組み込みでimmutableとして定義されているものに限り**この最適化が働きます。 >lst2d = [a, b] のシャローコピーは [a, b] であり、 >では aa = [a, a], bb = [b, b] のとき、lst3d = [aa, bb] のシャローコピーは何でしょうか。 それぞれlst2d[:]とlst3d[:]ではいけませんか? >全てが参照であるPythonについては、個人的にはむしろ一般のコピーはシャロ―コピーであって、**明示的に**イミュータブルな要素まで掘り下げてコピーすることがディープコピーなのだと考えています。階層の深さは気にしていません。 リファレンスでは複合オブジェクトに対する相違としています。オブジェクトが他オブジェクトへの参照を持っている場合、参照先を再帰的にコピー処理するかどうかの相違。 (一部、というか割と例外あり。たとえばdeep copyであっても__class__属性がコピーされることはない。上のintも例外の一つ(リファレンスに明示的には書かれていないようですが)) https://docs.python.org/ja/3/library/copy.html 「一般のコピー」なる概念が存在するかどうかそもそも疑問ですが、単一オブジェクトのコピーしか行わないshallow copyより再帰的にコピーするdeep copyの方が特殊な処理であることは間違いないでしょう。 >前述の定義に基けば arr2 = arr1 もシャロ―コピーになっちゃうのですよね 名前束縛はまた分けて考えるべきではないでしょうか。 lst2d = copy.copy(lst2d) は二回shallow copyされる、というのは不条理です。 shallow copyはコピー対象のオブジェクト「のみ」をコピーしてオブジェクトを一つ増やす操作、deep copyはコピー対象のオブジェクトとそれが参照するもの(の中で更に条件に合致したもの)を再帰的にコピーする操作。名前束縛はほとんど無関係だと思います(参照という仕組みは共有するにせよ)。
LouiS0616

2019/10/13 06:46 編集

> おそらく**組み込みでimmutableとして定義されているものに限り**この最適化が働きます。 一部のオブジェクトに関して効率化されているのは当然で、これは種々の思想を崩さないように思います。 ユーザから見てフルコピーされているように振舞えばそれはディープコピーだと考えます。 手元でちょっと試してみましたが、タプルについては内部まで辿ってくれていそうです。 tpl1 = ([1, 2], ) tpl2 = copy.deepcopy(tpl1) print(tpl1[0] is tpl2[0]) # False ミュータブルな要素を持つタプルはイミュータブルとは少し言いづらく、この動作は自然です。 > それぞれlst2d[:]とlst3d[:]ではいけませんか? 聞き方を変えます。 [aa[:], bb[:]] は [aa, bb] のシャローコピーですか?ディープコピーですか? リファレンスに従えばこれはシャロ―コピーで、そして私自身もそう思います。 シャロ―コピーは複数とおり存在し得ます。シャローコピーの定義は『ディープコピーでは無いコピー』だと捉えるのが自然です。 > たとえばdeep copyであっても__class__属性がコピーされることはない。上のintも例外の一つ イミュータブルだからでは。 > 「一般のコピー」なる概念が存在するかどうかそもそも疑問ですが、単一オブジェクトのコピーしか行わないshallow copyより再帰的にコピーするdeep copyの方が特殊な処理であることは間違いないでしょう。 特殊な処理だと言うこと、それには同意します。 概念的に言えば、Pythonでは特殊ですが、それこそCではディープコピーの方が自然でしょう。 > 名前束縛はほとんど無関係だと思います(参照という仕組みは共有するにせよ)。 そうですね。私自身読み返してみてちょっと強引だと感じました。シャローコピーはおろかそもそもコピーとも呼ばないですね。 arr2 = arr1 もシャローコピーかも、という部分は撤回させて下さい。
LouiS0616

2019/10/13 06:43 編集

実装/仕様レイヤでは、シャロ―コピー/ディープコピーは区別できないと考えます。 ・ シャローコピーを明確に定義することは難しく、『ディープコピー以外のコピー』だと考えるのが簡単。 ・ 一方ディープコピーも例外的な挙動が多く、完全には定義し難い。ディープコピーは可能な範囲で参照先の値を複製するが、ときに十全性より効率性が重視される。 --- 実際には、内部動作よりユーザの意思が重視されるように思います。 ・ [a, b, c].copy()/copy.copy(x) は a, b, c, x の型に関わらず常にシャローコピーを返す。 ・ copy.deepcopy(x) は x の型に関わらず常にディープコピーを返す。 この原則に基けば [a, b, c][:] でシャローコピーを取ろうなんて邪の邪ですが、習慣的に受け入れられているので認めることとします。というか私も多用します。
hayataka2049

2019/10/13 15:39 編集

>[aa[:], bb[:]] は [aa, bb] のシャローコピーですか?ディープコピーですか? >リファレンスに従えばこれはシャロ―コピーで、そして私自身もそう思います。 これには同意できません。 > 浅いコピー (shallow copy) は新たな複合オブジェクトを作成し、その後 (可能な限り) 元のオブジェクト中に見つかったオブジェクトに対する 参照 を挿入します。 > https://docs.python.org/ja/3/library/copy.html?highlight=%E3%82%B3%E3%83%94%E3%83%BC 参照するものがaa[:]であってaaではない以上、浅いコピーとはみなせないと考えます。[lst3d[0], lst3d[1]]ならみなせるのでしょうが。 私としては、以下の定義で特に不満を覚えません。 ・浅いコピーはコピー対象のオブジェクト**のみ**コピーを行う。 ・深いコピーは(厳密な定義はさておき)可能な限り再帰的に参照をたどり参照先をすべてコピーして挿入する。 この定義は必然的に、浅いコピー、深いコピー以外の中途半端なコピーの存在を導いてしまいますが、それはそれで別にあっても良いかと思います。特殊ではないので名前がないだけです。[aa[:], bb[:]]などは(スライスで全要素取得するのがシャローコピーとみなせるとして)その位置づけでどうでしょうか。
hayataka2049

2019/10/13 15:46

ところでnumpy配列ですが、なるほど上の私の定義で行くとシャローコピーになります。 ・内部で保持しているものがPyObjectポインタ(値型)以外の場合は、原則的には単一オブジェクトのコピーを行うだけなのでシャローコピーと呼んでも差し支えない(あえてそう言うまでもありませんが) ・内部で保持しているものがPyObjectポインタ(値型)であれば、複合オブジェクトとして見ることにするがこの場合の動作もシャローコピーになる 実際にはメモリ領域がまるごと複製され、そこに格納されている値もコピーされるので内部に含まれる要素の実体がコピーされるという意味ではdeepっぽいのではという話でしたが、これをdeepと呼ぶのは確かに不適当でしょうから、取り下げます。 あとは(あえてそう言うまでもありませんが)の部分が気になるくらいで、特段区別する必要がないと思うので、個人的には単なるコピーと称することを好みます。
LouiS0616

2019/10/14 10:48

私自身は、やはり実装に立ち入ることは好みません。 多くのプログラマにとっては『どのように使ったらどのように働くか』が最も重要であると考えるからです。 シャローコピー/ディープコピーの定義については、hayataka2049さんの解釈がよりリファレンスの記述に沿っていると思います。私の解釈は (可能な限り) を無視したものでした。 名も無きコピーが間隙にあるのは正直腑に落ちませんが、少なくともPythonはそのように捉えていることを理解しました。
LouiS0616

2019/10/14 11:08

シャローコピーと回答に書いてあるのには、質問者さんに検索や考察を促す狙いがあります。 リストのリスト のシャローコピーを安易に取り、嵌る初心者を多く見てきました。 ndarrayに関しては語弊のある表現なのかもしれませんが、今後も使っていくつもりです。ndarrayと組み込みリストは、差を強く意識せずとも使えるものであって欲しいからです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問