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

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

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

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

Q&A

解決済

2回答

1584閲覧

構造の異なる辞書をソートしたい

k0908

総合スコア102

Python

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

0グッド

0クリップ

投稿2018/05/10 06:56

編集2018/05/10 08:19

構造の異なる辞書をソートしたい。
辞書dfには

df = [{"A":{"A1":{"a1":100,"b1":200,"c1":300}}},{"B":{"B1":{"a2":150,"b2":250,"c2":350}}},{"C":{"test1":10,"test2":190,"test3":120}},{"D":{"test01":170,"test02":150,"test03":180}}]

という風に

{‘A’:{‘A1’:{‘a1’:100,’b1’:200,’c1’:300}}}

という形の辞書と

{’C’:{‘test1’:10,’test2’:80,’test3’:120}}

という形の辞書が含まれている。

これらのdfの子辞書のvalue(100・200・10など)を小さいもの順に並べたい。
理想のアプトプットは、

C→
test1:10
A⇨A1→
a1:100
B⇨B1→
a2:150

のように並び変える事である。
もしdfの子辞書のvalueでタイがあれば、AとかBとかのkeyが小さいもの順に並び替えたい。

df = [{"A":{"A1":{"a1":100,"b1":200,"c1":300}}},{"B":{"B1":{"a2":150,"b2":250,"c2":350}}},{"C":{"test1":10,"test2":190,"test3":120}},{"D":{"test01":170,"test02":150,"test03":180}}] for i in range(len(df)): for key,value in sorted(df[i].items(), key=lambda x:x[0]): print(str(key)+ "⇨") x = str(key)+ "→" for ky,vl in value.items(): print(str(ky)+ "→") y = str(ky)+ "→" for k, v in sorted([(k, v) for k,v in vl.items() if type(v) is not list], key=lambda x: x[1]): print(str(k) + ": " + str(v))

とコードを書くと、AttributeError: 'numpy.float64' object has no attribute 'items’とネストが深くない要素のようでエラーが出た。
(もしかしたら、AttributeError: 'int' object has no attribute 'items' と出るかも)
エラーの原因はわかるが、僕がやりたいことをどうコードを書けばできるのかがわからない。そもそもプログラムでできるのかもわからない。

どのようにコードを書いて修正すればいいか?

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

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

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

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

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

hayataka2049

2018/05/10 07:34

一番上はsetになってますけど、それで良いんですか? あと、これをやらないで済ます手立てはないの・・・(前の質問でも同じことをLouiS0616さんに言われてたみたいですけど)
k0908

2018/05/10 07:42

setになっているというのはどういうことでしょうか?はい、今回はこの2つの辞書を変更できません。。。
hayataka2049

2018/05/10 07:49

setになっているっていうのは、そのままの意味です。{key:value,...}は辞書、{value, ...}はsetです。もっというと、辞書はsetの中には入れられないので、質問の最初に出てるものをそのまま打ち込むと「TypeError: unhashable type: 'dict'」とか出てきます
k0908

2018/05/10 07:56

すみません、変更以前の前のコードを載せていました。辞書dfはリストの中に入っており、今for文を使いそれぞれの要素を取り出して使っています。
hayataka2049

2018/05/10 08:01

その修正されたコードも同じエラーが出るんですが・・・手元で確認してないんですか?
can110

2018/05/10 08:07

提示エラーが再現できません。コードの一部ではなく、現象が再現する最低限で完全なコードを提示ください。
k0908

2018/05/10 08:11

本当にすみません!!dfが間違っていました。修正したものでは動く(確認済み)ので、もしお分かりでしたらお願いいたします。
can110

2018/05/10 08:16

「for i in range(len(df)):」行にて「IndentationError: unexpected indent」が発生します。
k0908

2018/05/10 08:20

おや、何故でしょう・・・。手元のコードをそっくりそのままコピーしたものを質問文に載せました。よろしければこちらをお使いください。
guest

回答2

0

私ならデータ構造を作り直してソートします。
以下適当ですが、それなりに動作します。

Python

1# 階層構造の辞書から要素のリストを作成 2# 要素は 値(val), 階層構造(tree)を持つ。 3def remake_data( dic, tree): 4 dest = [] 5 for key, val in dic.items(): 6 if isinstance( val, dict): 7 dest.extend( remake_data( val, tree + [key])) 8 else: 9 dest.append( {'val':val, 'tree':tree + [key]}) 10 return dest 11 12# 要素のソート 13def cmp_data( v1, v2): 14 # 値が最優先 15 cmp = v1['val'] - v2['val'] 16 if cmp != 0: 17 return cmp 18 19 # 次に階層名 20 for t1,t2 in zip(v1['tree'],v2['tree']): 21 if t1 != t2: 22 return t1 < t2 23 return 0 24 25# 要素を文字列化(適当) 26def to_str( data): 27 return '{}:{}'.format( data['tree'], data['val']) 28 29 30# 元データ 31df = [{"A":{"A1":{"a1":100,"b1":200,"c1":300}}},{"B":{"B1":{"a2":150,"b2":250,"c2":350}}},{"C":{"test1":10,"test2":190,"test3":120}},{"D":{"test01":170,"test02":150,"test03":180}}] 32print(df) 33 34# 扱いやすいデータ構造に作りかえ 35datas = [] 36for dic in df: 37 datas.extend( remake_data( dic, [])) 38[print(to_str(d)) for d in datas] 39 40print('ソート後') 41import functools 42datas = sorted( datas, key=functools.cmp_to_key(cmp_data)) 43[print(to_str(d)) for d in datas]

投稿2018/05/10 09:05

can110

総合スコア38262

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

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

0

ベストアンサー

こんなの考えたくもない(手に負えない)ので、再帰でflattenするコード書きました。あんまりうまくない部分もありますが。

python

1from pprint import pprint 2 3df = [{"A":{"A1":{"a1":100,"b1":200,"c1":300}}},{"B":{"B1":{"a2":150,"b2":250,"c2":350}}},{"C":{"test1":10,"test2":190,"test3":120}},{"D":{"test01":170,"test02":150,"test03":180}}] 4 5def parse(d): 6 if len(d.keys()) != 1: 7 return {(k,):v for k,v in d.items()} 8 else: 9 key = list(d.keys())[0] 10 val = list(d.values())[0] 11 12 child = parse(val) 13 14 ret_d = {} 15 for k,v in child.items(): 16 k_lst = list(k) 17 k_lst.insert(0, key) 18 ret_d[tuple(k_lst)] = v 19 return ret_d 20 21d_flatten = {} 22for d in df: 23 d_flatten.update(parse(d)) 24 25pprint(d_flatten) 26""" 27{('A', 'A1', 'a1'): 100, 28 ('A', 'A1', 'b1'): 200, 29 ('A', 'A1', 'c1'): 300, 30 ('B', 'B1', 'a2'): 150, 31 ('B', 'B1', 'b2'): 250, 32 ('B', 'B1', 'c2'): 350, 33 ('C', 'test1'): 10, 34 ('C', 'test2'): 190, 35 ('C', 'test3'): 120, 36 ('D', 'test01'): 170, 37 ('D', 'test02'): 150, 38 ('D', 'test03'): 180} 39"""

あとはitems()でもして多重キーのソートかければできるでしょう、たぶん。

参考:
多重キーでのソート - Pashango’s Blog

投稿2018/05/10 08:52

hayataka2049

総合スコア30933

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

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

k0908

2018/05/11 05:26

コードの意味を理解するのに時間がかかってしまいましたが、できました!ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問