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

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

新規登録して質問してみよう
ただいま回答率
85.37%
iteratorパターン

iteratorパターンとは、オブジェクト指向プログラミングのデザインパターンです。コンテナオブジェクトの要素を列挙する手段を独立させることによって、コンテナの内部仕様に依存しない反復子を提供することを目的とします。

Python

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

Q&A

解決済

4回答

7985閲覧

[Python]多次元の辞書式配列を書いた順番に取り出したい

Gazelle

総合スコア136

iteratorパターン

iteratorパターンとは、オブジェクト指向プログラミングのデザインパターンです。コンテナオブジェクトの要素を列挙する手段を独立させることによって、コンテナの内部仕様に依存しない反復子を提供することを目的とします。

Python

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

1グッド

1クリップ

投稿2016/05/06 13:42

編集2016/05/06 13:44

環境

Pythonのバージョン: 2.7

やりたいこと

多次元の辞書式配列から書いた順を値を取り出したい。かつ、簡単に値を定義できる。

もうちょっと詳しく

以下のような適当な辞書式の配列があるとします。
(※以下に示すデータには全く意味がありません)

python

1sample_dict = { 2 "Device" : { 3 "os": ("ios", "android", "firefox", "ubuntu"), 4 "size": ("A", "B", "C") 5 }, 6 "Mode": { 7 "input": {"address", "mail", "tel"}, 8 "output": {"start_time", "end_time"}, 9 "update": { 10 "editor": {"title", "body"} 11 } 12 } 13}

このデータを書いた順番に取り出して行きたいのですが、辞書式なので書いた順に取り出せるとは限りません。

試しに、先の``sample_dict```を標準出力させると、次のようになります。

sh

1{'Device': {'os': ('ios', 'android', 'firefox', 'ubuntu'), 'size': ('A', 'B', 'C')}, 'Mode': {'input': set(['mail', 'tel', 'address']), 'update': {'editor': set(['body', 'title'])}, 'output': set(['start_time', 'end_time'])}}

末尾の記述が最初に書いた順番と異なります(仕様)。これは、当方がしたいこととは異なります。

試したこと

順序だった辞書式配列はどうやら作れるようで、ドキュメント(8.3.6. OrderedDict オブジェクト)に有るように、OrderedDictを試みました。

かりに、sample_dictをOrderedDictで表現すると、

sample_dict = OrderedDict() device_data = OrderedDict() device_data["os"] = ("ios", "android", "firefox", "ubuntu") device_data["size"] = ("A", "B", "C") # Modeの方は省略 sample_dict["Device"] = device_data

というように、やや冗長な感じがします。

どのように知りたいか

頑張ればOrderedDictで入力する値を定義できるのですが、なにせ書くのが面倒だなぁ、というのが正直なところです。このような経緯から質問しようと至ったわけです。

すなわち、いま達成したいことは、次の2点です。

  1. 順序だった辞書式配列(jsonでも可)でデータを定義したい
  2. 1.の時の定義をより簡潔にしたい。

もっとスマートに書く方法をご存知のかたいらっしゃいましたら、ご助力のほどよろしくお願いします。

質問の情報が不足しておりましたら、ご指摘下さい。

ikuwow👍を押しています

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

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

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

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

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

guest

回答4

0

自己解決

自己解決方法

teamikl様、raccy様の回答に有りますように

python

1json.JSONDecoder(object_pairs_hook=OrderedDict).decode(raw_text)

を使って処理する方法、大変参考になりました。ただ、入力値の書き方JSONなので、やや見づらいなあと思いながら

raccy様のコメント

※ どうしても、リテラルで普通に書きたいんじゃ!と言うのであれば、Rubyに浮気するしか無いです…。

を見たところピンッと来て、ちょっと検索の方法を変えて見ました。
つまり、YAML形式で設定した値がOrderedDictで返ってくれば最高じゃないか。。。と思って検索したら、

Stack Overflow: In Python, how can you load YAML mappings as OrderedDicts?

ありました。JSONも良かったのですが、人間的にはYAMLのほうが見やすいためこちらを採用させていただきました。したがって、自己解決としようと思います。

ご回答者の皆様、回答ありがとうございました。

以下にサンプルコードを載せますので、同じ疑問を抱いた方はぜひ使って下さい。

準備

以下の2つをpipでインストールして下さい。

requirements.txt

1pyyaml 2yamlordereddictloader

サンプルコード

※Python 2.7で動作を確認しております。

同じディレクトリ中に

  • main.py
  • od_keys.json
  • od_keys.yml

を用意します。中身は次の通り。

次のようにコードを書きます。

main.py

Python

1# -*- coding: utf-8 -*- 2from collections import OrderedDict 3import json 4import yaml, yamlordereddictloader 5import os 6 7def load_ordinary_dict_key(file_path): 8 ext = os.path.splitext(file_path)[1] # 拡張子を取得 9 if ext == ".json": 10 # JSON形式で値を取得する場合 11 f = open(file_path) 12 raw_text = f.read() 13 f.close() 14 return json.JSONDecoder(object_pairs_hook=OrderedDict).decode(raw_text) 15 if ext == ".yml" or ext == ".yaml": 16 # YAML形式で値を取得する場合 17 return yaml.load(open(file_path), Loader=yamlordereddictloader.Loader) 18 19if __name__ == '__main__': 20 json_od_keys = load_ordinary_dict_key("od_keys.json") 21 yml_od_keys = load_ordinary_dict_key("od_keys.yml") 22 23 print json_od_keys 24 print yml_od_keys

od_keys.json

json

1{ 2 "Device": { 3 "os": [ 4 "ios", 5 "android", 6 "firefox", 7 "ubuntu" 8 ], 9 "size": [ 10 "A", 11 "B", 12 "C" 13 ] 14 }, 15 "Mode": { 16 "input": [ 17 "address", 18 "mail", 19 "tel" 20 ], 21 "output": [ 22 "start_time", 23 "end_time" 24 ], 25 "update": { 26 "editor": [ 27 "title", 28 "body" 29 ] 30 } 31 } 32}

od_keys.yml

yml

1Device: 2 os: 3 - ios 4 - android 5 - firefox 6 - ubuntu 7 size: 8 - A 9 - B 10 - C 11Mode: 12 input: 13 - address 14 - mail 15 - tel 16 update: 17 editor: 18 - title 19 - body

出力

JSON Version

sh

1OrderedDict([(u'Device', OrderedDict([(u'os', [u'ios', u'android', u'firefox', u'ubuntu']), (u'size', [u'A', u'B', u'C'])])), (u'Mode', OrderedDict([(u'input', [u'address', u'mail', u'tel']), (u'output', [u'start_time', u'end_time']), (u'update', OrderedDict([(u'editor', [u'title', u'body'])]))]))])

YAML Version

sh

1OrderedDict([('Device', OrderedDict([('os', ['ios', 'android', 'firefox', 'ubuntu']), ('size', ['A', 'B', 'C'])])), ('Mode', OrderedDict([('input', ['address', 'mail', 'tel']), ('update', OrderedDict([('editor', ['title', 'body'])]))]))])

投稿2016/05/07 02:24

編集2016/05/07 02:28
Gazelle

総合スコア136

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

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

Gazelle

2016/05/07 02:26

あ、書く場所ココじゃない・・・・。回答は削除できないのかぁぁぁ・・・
raccy

2016/05/07 03:33

いえいえ、自己解決ならここで問題ありませんよ。よりベターな方法があって、それを知ることが一番良いのであり、みんなも助かりますからね。
guest

0

回答ではありませんが、OrderedDict についての参考情報を紹介します。

d = OrderedDict(one=1, two=2, three=3)
print d

最初のdはえっっっ!と思うが、
OrderedDict([(‘one’, 1), (‘three’, 3), (‘two’, 2)])
のように表示されてしまう。
...
追加 した順番を記憶するとあるだけです。書き込んだ順番は維持してくれない。。。
...
もっと簡単に順番も維持されてもっと簡単に書き込む方法ないの?
下記DLようにタプルにしてやると、順番通り突っ込めます。
DL = (('four',4), ('five',5), ('six',6))
d2 = OrderedDict(DL)
d1.update(d2)
print d1
for i in d1:
print i, d1[i]
...

投稿2016/05/07 00:32

katoy

総合スコア22324

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

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

Gazelle

2016/05/07 02:00

katoy様、回答有り難うございます。
guest

0

jsonであればこんな感じでしょうか。sample_dictとsample_ordered_dictを見比べてみてください。

Python

1from __future__ import print_function 2from collections import OrderedDict 3import json 4 5sample_json = """ 6{ 7 "Device": { 8 "os": ["ios", "android", "firefox", "ubuntu"], 9 "size": ["A", "B", "C"] 10 }, 11 "Mode": { 12 "input": ["address", "mail", "tel"], 13 "output": ["start_time", "end_time"], 14 "update": { 15 "editor": ["title", "body"] 16 } 17 } 18} 19""" 20sample_dict = json.JSONDecoder().decode(sample_json) 21print(sample_dict) 22sample_ordered_dict = json.JSONDecoder( 23 object_pairs_hook=OrderedDict).decode(sample_json) 24print(sample_ordered_dict)

参考: stackoverflow: Can I get JSON to load into an OrderedDict in Python?

※ どうしても、リテラルで普通に書きたいんじゃ!と言うのであれば、Rubyに浮気するしか無いです…。

投稿2016/05/07 00:03

raccy

総合スコア21737

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

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

Gazelle

2016/05/07 02:00

raccy様、回答ありがとうございます。 JSONDecorderのサンプルありがとうございます。 > ※ どうしても、リテラルで普通に書きたいんじゃ!と言うのであれば、Rubyに浮気するしか無いです…。 確かにRubyだったらなぁ、と思いながら書いていました。 ただ、こちらのコメント、検索の良いヒントとなりました。ありがとうございました!
guest

0

設定ファイル的な用途だと ConfigParser はどうでしょう。
データの取り出し方等は変わりますが、2.7以降であればデフォルトで OrderedDict です。
辞書のネストは出来ないので、必要とするデータ構造の条件と合えばですが、
文字列のクォートを省く等、定義の記述は簡素化できます。

また、JSONであれば object_pairs_hook オプションで OrderedDict を使うよう指定可能です。
json.load(open("sample.json"), object_pairs_hook=collections.OrderedDict)

投稿2016/05/06 19:24

teamikl

総合スコア8681

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

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

Gazelle

2016/05/07 01:58

teamikl様、回答ありがとうございます。 ConfigParserを早速試しました。 > 辞書のネストは出来ないので、... と仰るとおり、今回のようなデータが多層化された場合ですと不向きかな、と感じました。ただ、このようなConfigParserについては触ったことがなかったので良い勉強となりました。ありがとうございます。 > また、JSONであれば object_pairs_hook オプションで OrderedDict を使うよう指定可能です。 > json.load(open("sample.json"), object_pairs_hook=collections.OrderedDict) こちら、やりたいこととして完璧でした。object_pairs_hookを使う方法は初めて知りました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問