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

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

ただいまの
回答率

90.35%

  • Python

    9121questions

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

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 304

k0908

score 85

構造の異なる辞書をソートしたい。
辞書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' と出るかも)
エラーの原因はわかるが、僕がやりたいことをどうコードを書けばできるのかがわからない。そもそもプログラムでできるのかもわからない。

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • k0908

    2018/05/10 17:11

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

    キャンセル

  • can110

    2018/05/10 17:16

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

    キャンセル

  • k0908

    2018/05/10 17:20

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

    キャンセル

回答 2

checkベストアンサー

+2

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

from pprint import pprint

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}}]

def parse(d):
    if len(d.keys()) != 1:
        return {(k,):v for k,v in d.items()}
    else:
        key = list(d.keys())[0]
        val = list(d.values())[0]

        child = parse(val)

        ret_d = {}
        for k,v in child.items():
            k_lst = list(k)
            k_lst.insert(0, key)
            ret_d[tuple(k_lst)] = v
        return ret_d

d_flatten = {}
for d in df:
    d_flatten.update(parse(d))

pprint(d_flatten)
"""
{('A', 'A1', 'a1'): 100,
 ('A', 'A1', 'b1'): 200,
 ('A', 'A1', 'c1'): 300,
 ('B', 'B1', 'a2'): 150,
 ('B', 'B1', 'b2'): 250,
 ('B', 'B1', 'c2'): 350,
 ('C', 'test1'): 10,
 ('C', 'test2'): 190,
 ('C', 'test3'): 120,
 ('D', 'test01'): 170,
 ('D', 'test02'): 150,
 ('D', 'test03'): 180}
"""

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/11 14:26

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

    キャンセル

+2

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

# 階層構造の辞書から要素のリストを作成
# 要素は 値(val), 階層構造(tree)を持つ。
def remake_data( dic, tree):
    dest = []
    for key, val in dic.items():
        if isinstance( val, dict):
            dest.extend( remake_data( val, tree + [key]))
        else:
            dest.append( {'val':val, 'tree':tree + [key]})
    return dest

# 要素のソート
def cmp_data( v1, v2):
    # 値が最優先
    cmp = v1['val'] - v2['val']
    if cmp != 0:
        return cmp

    # 次に階層名
    for t1,t2 in zip(v1['tree'],v2['tree']):
        if t1 != t2:
            return t1 < t2
    return 0

# 要素を文字列化(適当)
def to_str( data):
    return '{}:{}'.format( data['tree'], data['val'])


# 元データ
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}}]
print(df)

# 扱いやすいデータ構造に作りかえ
datas = []
for dic in df:
    datas.extend( remake_data( dic, []))
[print(to_str(d)) for d in datas]

print('ソート後')
import functools
datas = sorted( datas, key=functools.cmp_to_key(cmp_data))
[print(to_str(d)) for d in datas]

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Python

    9121questions

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