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

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

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

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

Q&A

解決済

1回答

496閲覧

OrderedDict()と辞書型と要素の順番について

退会済みユーザー

退会済みユーザー

総合スコア0

Python

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

0グッド

0クリップ

投稿2017/11/01 07:17

編集2017/11/01 07:23

プログラミング初学者です
https://www.hackerrank.com/challenges/most-commons/problem

この問題を解いていて

python

1from collections import OrderedDict 2 3user = sorted(input()) 4counter = OrderedDict() 5 6for i in user: 7 if i in counter: 8 counter[i] += 1 9 else: 10 counter[i] = 1 11 12n = 0 13for k, v in sorted(counter.items(), key=lambda x:x[1], reverse=True): 14 n += 1 15 if n > 3: 16 break 17 else: 18 print(k, v)

まずこのように解きました
forループの部分をCounter()に代えようと考え

python

1from collections import Counter 2 3user = sorted(input()) 4counter = Counter(user) 5 6n = 0 7for k, v in sorted(counter.items(), key=lambda x:x[1], reverse=True): 8 n += 1 9 if n > 3: 10 break 11 else: 12 print(k, v)

とこのように変えたのですが、outputの順番が同じ回数のもの同士で変わってしまいます
何故順番が安定しないのか、また何故最初のコードは順番が固定されるのか
もし後者のコードの順序を固定させるにはどのような方法が考えられるのか
教えていただきたいです
正直OrderdDict()の理解が浅いのでもしそれが関係しているなら解説いただけるとありがたいです
よろしくお願いします

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

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

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

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

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

guest

回答1

0

ベストアンサー

リンク先の問題を見る限り...

Output Format
Print the three most common characters along with their occurrence count each on a separate line.
Sort output in descending order of occurrence count.
If the occurrence count is the same, sort the characters in ascending order.

ここでのascendingとは、アルファベット順のことではないでしょうか?
そう解釈してよいのなら、辞書に要素を追加した順を意識する必要はないはずです。
Counter.most_commonで出現回数順に並び変え、その後にアルファベット順にソートすればよいかと。

Python

1from collections import Counter 2 3counter = Counter(input()) 4 5for k, v in sorted(counter.most_common(), key=lambda x: x[0])[:3]: 6 print(k, v)

動作テストはしていないので、何かバグがあるかもしれませんが。
追記:バグ、ありました。ちょっと修正します。


修正しました。結局Counter.most_commonは使ってないです。

Python

1from collections import Counter 2 3counter = Counter(input()) 4for k, v in sorted(counter.items(), key=lambda x: (-x[1], x[0]))[:3]: 5 print(k, v)

さらに改造しました。こっちの方がわかりやすい気もしますね。

Python

1from collections import Counter 2from operator import itemgetter 3 4counter_list = list(Counter(input()).items()) 5counter_list.sort(key=itemgetter(0)) 6counter_list.sort(key=itemgetter(1), reverse=True) 7 8for k, v in counter_list[:3]: 9 print(k, v)

順番が安定しない理由

Counterは要素の挿入順序を記憶しないからです。
引用元:Python標準ライブラリ - 8.3.2. Counter オブジェクト

class collections.Counter([iterable-or-mapping])
Counter はハッシュ可能なオブジェクトをカウントする dict のサブクラスです。これは、要素を辞書のキーとして保存し、そのカウントを辞書の値として保存する、順序付けされていないコレクションです。

一方、OrderedDictは要素の挿入順序を記憶します。
引用元:Python標準ライブラリ- 8.3.6. OrderedDict オブジェクト

class collections.OrderedDict([items])
通常の dict メソッドをサポートする、辞書のサブクラスのインスタンスを返します。 OrderedDict は、キーが最初に追加された順序を記憶します。新しい項目が既存の項目を上書きしても、元の挿入位置は変わらないままです。

このように、これらの用途は異なります。
なお、OrderedCounterたるクラスが実装例として紹介されています。

順序付き辞書と Counter クラスを組み合わせると、要素が最初に現れた順を記憶するカウンタができます:

class OrderedCounter(Counter, OrderedDict): 'Counter that remembers the order elements are first encountered'
def __repr__(self): return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self): return self.__class__, (OrderedDict(self),)

投稿2017/11/01 07:40

編集2017/11/01 08:02
LouiS0616

総合スコア35660

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

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

退会済みユーザー

退会済みユーザー

2017/11/01 07:47

後からアルファベット順にソートしたら出現回数まで入れ替わってしまいませんか
LouiS0616

2017/11/01 07:49

ですよね。実行するまで気付かなかった私がまぬけでした。 既に修正済みでるので、更新してご覧ください。
退会済みユーザー

退会済みユーザー

2017/11/01 07:53

回答ありがとうございます、これから読んで理解してベストアンサーにすると思います
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問