質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python

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

Q&A

解決済

2回答

3282閲覧

配列の要素の順位付けをしたい。

SmaSTATION

総合スコア29

Python

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

1グッド

1クリップ

投稿2022/10/16 00:46

前提

a=[12,43,7,15,9] の配列の要素を小さい順に並べたときのように順位で表示したいです。
a=[12,43,7,15,9]であれば、
出力結果は(2,4,0,3,1)です。

実現したいこと

個人的にはaの配列をソートして、新しい配列を作り、その配列の順番をaの配列に反映させるプログラムを作ってみたいと思っています。

下記のプログラムはソートしたとこで終わっています。
ここからどうすればいいでしょうか。

該当のソースコード

Python

1a=[12,43,7,15,9] 2 3new_list=sorted(a) 4 5//aの配列をソートした新しい配列の要素番号をaに対応付けしたい...

試したこと

ソートする方法とかはたくさんあると思うのですが、順位を反映させるというものが見つからず困ってます。

Cocode👏を押しています

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

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

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

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

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

lehshell

2022/10/16 01:20

SmaSTATION さん a=[12,43,7,15,9] とありますが、リスト内に同じ数字があった場合の期待する出力結果を記載しましょう。 2人の方はそれぞれ異なる受け取り方をされています。
guest

回答2

0

リスト内に重複する要素がない場合。

python

1>>> a = [12, 43, 7, 15, 9] 2>>> [sorted(a).index(x) for x in a] 3[2, 4, 0, 3, 1]

投稿2022/10/16 01:03

編集2022/10/16 01:06
melian

総合スコア19791

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

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

0

ベストアンサー

個人的にはaの配列をソートして、新しい配列を作り、その配列の順番をaの配列に反映させるプログラムを作ってみたいと思っています。

これを実現すると以下になります.

Python

1a = [12, 43, 7, 15, 9] 2new_list = sorted(a) # aの配列をソートして、新しい配列を作り 3 4rank = [0] * len(a) 5for i in range(len(new_list)): # その配列の順番を 6 for j in range(len(a)): # aの配列に 7 if new_list[i] == a[j]: 8 rank[j] = i # 反映させる 9 10print(rank) # [2, 4, 0, 3, 1]

配列の要素とその順番が一致しているかどうか判定するのに2重のループになっているため,要素数Nに対して時間計算量O(N^2)のアルゴリズムとなっており,非常に低速な実装です.また,要素に重複がある場合正しく動作しないので,もっとコードを書く必要があります.

この問題を解決すべく,ソートする際に,元の配列のインデックス情報の方を並び替えてしまえば良い,という発想が必要になります.ここではソートにかかる時間計算量そのままO(N log N)で済みます.

これは一般に,argsort()と呼ばれる動作になり,順位を求める実装と合わせて次のようになります.

Python

1def argsort(arr, reverse = False): # ソート前のindexを返す 2 return sorted(range(len(arr)), key = arr.__getitem__, reverse = reverse) 3 4a = [12, 43, 7, 15, 9] 5rank = [0] * len(a) 6for r, idx in enumerate(argsort(a)): # r: 順位, idx: argsortで求めたソート前のindex 7 rank[idx] = r # ソート前のindexであるidxを使ってrank配列のidx番目の順位をrにする 8print(rank) # [2, 4, 0, 3, 1]

また,argsort()の実装方法はこれに限りません.あくまで一例です.他にも

Python

1def argsort(arr, reverse = False): 2 return [x for x, y in sorted(enumerate(arr), key = lambda x: x[1], reverse = reverse)]

などがあります.なお基本構造はどれも同じで,ソートの対象keyの指定を,key = arr.__getitem__として値を指定するか,enumerate()で列挙される要素の1番目に対象の値があることを利用したkey = lambda x: x[1]とするなど,複数のテクニックが存在します.ソートの対象はリストの値,実際に並び替えられたのはリストのインデックス.といった具合です.

stack overflow - How to get indices of a sorted array in Python

今回はこれを使ってindexを保持したソートをすることで,O(N log N)の時間計算量で順位を反映させることができました.
このままだと同じ値でも別々の順位を割り振られる実装になっていますので,次のように変更することもできます.

Python

1rank = [0] * len(a) 2rank_no = set() 3for idx in argsort(a): 4 rank_no.add(a[idx]) 5 rank[idx] = len(rank_no)

余談ですが「たまたま」例示いただいたデータ[12, 43, 7, 15, 9]においてargsort()の結果と求めた順位rankが同じになっています(非常にややこしいです).argsort()の結果を例示しなかったのは混乱するからです...

結論

Python

1import random 2 3def argsort(arr, reverse = False): 4 return sorted(range(len(arr)), key = arr.__getitem__, reverse = reverse) 5 6def calc_rank1(arr, reverse = False): # 重複があっても左から順に順位付け 7 rank = [0] * len(arr) 8 for r, idx in enumerate(argsort(arr, reverse)): 9 rank[idx] = r 10 return rank 11 12def calc_rank2(arr, reverse = False): # 重複は同じ順位 13 rank = [0] * len(arr) 14 rank_no = set() 15 for idx in argsort(arr, reverse): 16 rank_no.add(arr[idx]) 17 rank[idx] = len(rank_no) - 1 18 return rank 19 20a = [random.randint(0, 20) for _ in range(10)] 21 22print("original:", a) # [9, 6, 9, 19, 9, 9, 15, 3, 10, 12] 23print("argsort :", argsort(a)) # [7, 1, 0, 2, 4, 5, 8, 9, 6, 3] 24print("rank1 :", calc_rank1(a)) # [2, 1, 3, 9, 4, 5, 8, 0, 6, 7] 25print("rank2 :", calc_rank2(a)) # [2, 1, 2, 6, 2, 2, 5, 0, 3, 4]

投稿2022/10/16 01:05

編集2022/10/16 05:46
PondVillege

総合スコア1579

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問