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

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

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

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

3回答

1864閲覧

Python辞書表記:同一キーの取り扱いについて

退会済みユーザー

退会済みユーザー

総合スコア0

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/03/03 07:17

編集2020/03/03 08:01

Pythonの辞書機能を使って, Live2Dの専用ソフトウェアに読み込ませることが出来るモデルファイルのJSONを作ろうと考えています.

具体的なコード, 実装したいこと

モデルファイルのサンプルをこちらに貼付します.

JSON

1#model.json 2 3{ 4 "model":"XXX.moc", 5 "textures":[ 6 "XXX.png" 7 ], 8 "motions":{ 9 "idle":[ 10 {"file":"../motion/angry01.mtn"} 11 {"file":"../motion/angry02.mtn"}, 12 {"file":"../motion/bye01.mtn"}, 13 {"file":"../motion/cry01.mtn"}, 14 {"file":"../motion/idle01.mtn"}, 15 {"file":"../motion/idle02.mtn"}, 16 {"file":"../motion/kime01.mtn"}, 17 {"file":"../motion/nf01.mtn"}, 18 {"file":"../motion/nf02.mtn"}, 19 {"file":"../motion/nf03.mtn"}, 20 {"file":"../motion/nf04.mtn"}, 21 {"file":"../motion/nf05.mtn"}, 22 {"file":"../motion/nf_left01.mtn"}, 23 {"file":"../motion/nf_right01.mtn"}, 24 {"file":"../motion/pui01.mtn"}, 25 {"file":"../motion/sad01.mtn"}, 26 {"file":"../motion/serious01.mtn"}, 27 {"file":"../motion/shame01.mtn"}, 28 {"file":"../motion/smile01.mtn"}, 29 {"file":"../motion/smile02.mtn"}, 30 {"file":"../motion/smile03.mtn"}, 31 {"file":"../motion/sneeze01.mtn"}, 32 {"file":"../motion/surprised01.mtn"} 33 ] 34 } 35}

"motions":{
"idle":[
以下はPythonの辞書的な説明をするなら"file"がキー, "../motion/XXXXX.mtn"がバリューに相当します.

現在, 特定フォルダに格納されているファイルをスキャンし, そのファイルの情報をmodel.json にまとめる, というプログラムを作成しています.

ですが, "motions"以下のグループを書き出す際, Pythonの辞書配列では同階層に同じキーは存在することが出来ないため, 要素編集や辞書連結等を使って順々にキーを書き足していくことができず, 質問に参りました.

※※※ちなみに, この"file"のキーの名前は変更すると専用ソフトで認識できなくなるため, 別のキーの名前にするということはできません.

求めている解答

このようなJSONファイルをPythonで作る場合, 辞書以外に有効な方法はありますでしょうか? もしくはできればPythonで解決したいですが他に楽, 現実的に解決できそうな方法等ございますでしょうか?

###追記
実際に使用しているコードはこちらです

※フォルダ構成は
Live2D
┣ sample(必要なファイルはすべてこの中)
となっています. 

Python

1import os 2import glob 3import json 4 5os.chdir(os.path.dirname(os.path.abspath(__file__))) 6files = os.listdir("./live2D") 7files_dir = [f for f in files if os.path.isdir(os.path.join("./live2D", f))] 8 9for dir in files_dir : 10 dic = {"name":"Live2D","model":"moc/Live2D.moc","textures":["Texture2D/texture_00.png"],"motions":{"idle":[{"name":0,"file":0}],"tap":[{"name":0,"file":0}]},"expressions":[{"name":0,"file":0}],"physics":"physics/physics.json","lip_sync":"true"} 11 12 mocfiles = glob.glob('./live2D/'+str(dir)+'/**/*.moc') 13 dic["model"] = str(mocfiles)[len(dir)+13:-2].replace('\','/') 14 phyfiles = glob.glob('./live2D/'+str(dir)+'/**/*physics.json') 15 dic["physics"] = str(phyfiles)[len(dir)+13:-2].replace('\','/') 16 17 mtnfiles = glob.glob('./live2D/'+str(dir)+'/**/*.mtn') 18 exdic = {"idle":[{"name":0,"file":0}],"tap":[{"name":0,"file":0}]} 19 20 for mtn in mtnfiles: 21 exdic.update({"file":str(mtn)[len(dir)+10:].replace('\','/')}) 22 dic ["motions"].update(exdic) 23 24 with open (r"./Live2D/"+dir+"/model.json","w") as f: 25 f.write(json.dumps(dic, ensure_ascii=False, indent=4, sort_keys=False, separators=(',', ': '))) 26 print(json.dumps(dic, ensure_ascii=False, indent=4, sort_keys=False, separators=(',', ': '))) 27

実行結果

{ "name": "Live2D", "model": "moc/Live2D.moc", "textures": [ "Texture2D/texture_00.png" ], "motions": { "idle": [ { "name": 0, "file": 0 } ], "tap": [ { "name": 0, "file": 0 } ], "file": "motion/rokka_surprised02.mtn" }, "expressions": [ { "name": 0, "file": 0 } ], "physics": "physics/physics.json", "lip_sync": "true" }

このように"file": "motion/rokka_surprised02.mtn"しか出力されません. (これは名前順で最後のファイル)

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

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

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

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

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

guest

回答3

0

実行結果が見やすいようにこちらで。

質問がわかりません。

"idle"要素(array)の最初のデータの末尾に,が抜けていますが、そこさえ修正してしまえば、これ自体普通にPythonのオブジェクトとして解釈可能なコードになっています。

>>> d = { ... "model":"XXX.moc", ... "textures":[ ... "XXX.png" ... ], ... "motions":{ ... "idle":[ ... {"file":"../motion/angry01.mtn"}, (略) ... {"file":"../motion/surprised01.mtn"} ... ] ... } ... } >>> from pprint import pprint >>> pprint(d) {'model': 'XXX.moc', 'motions': {'idle': [{'file': '../motion/angry01.mtn'}, (略) {'file': '../motion/surprised01.mtn'}]}, 'textures': ['XXX.png']}

リテラルとして表現可能なオブジェクトである以上、Pythonの辞書で表現できないわけがありません。
純粋にコードに問題があるだけです。

ですが, "motions"以下のグループを書き出す際, Pythonの辞書配列では同階層に同じキーは存在することが出来ないため, 要素編集や辞書連結等を使って順々にキーを書き足していくことができず

この部分で、具体的にどういうコードを書いて何が起こったのかを書きましょう。
あなたがなにをしたのかまったく伝わりません。


"tap"がわからないので手を付けませんが、"idle"はこうじゃないですか?

python

1for dir in files_dir : 2 # dic = {"name":"Live2D","model":"moc/Live2D.moc","textures":["Texture2D/texture_00.png"],"motions":{"idle":[{"name":0,"file":0}],"tap":[{"name":0,"file":0}]},"expressions":[{"name":0,"file":0}],"physics":"physics/physics.json","lip_sync":"true"} 3 dic = {"name":"Live2D","model":"moc/Live2D.moc","textures":["Texture2D/texture_00.png"],"motions":{"idle":[],"tap":[{"name":0,"file":0}]},"expressions":[{"name":0,"file":0}],"physics":"physics/physics.json","lip_sync":"true"} 4 5 mocfiles = glob.glob('./live2D/'+str(dir)+'/**/*.moc') 6 dic["model"] = str(mocfiles)[len(dir)+13:-2].replace('\','/') 7 phyfiles = glob.glob('./live2D/'+str(dir)+'/**/*physics.json') 8 dic["physics"] = str(phyfiles)[len(dir)+13:-2].replace('\','/') 9 10 mtnfiles = glob.glob('./live2D/'+str(dir)+'/**/*.mtn') 11 12 for mtn in mtnfiles: 13 # dic["motions"]["idle"] が list 14 dic["motions"]["idle"].append({"file":str(mtn)[len(dir)+10:].replace('\','/')}) 15 16 with open (r"./Live2D/"+dir+"/model.json","w") as f: 17 f.write(json.dumps(dic, ensure_ascii=False, indent=4, sort_keys=False, separators=(',', ': '))) 18 print(json.dumps(dic, ensure_ascii=False, indent=4, sort_keys=False, separators=(',', ': ')))

dic["motions"]["idle"]を空リストで用意しておいて、新しい辞書をappendしていけばいいのでは。


というかこの感じなら

python

1for dir in files_dir: 2 mocfiles = glob.glob('./live2D/' + str(dir) + '/**/*.moc') 3 model_value = str(mocfiles)[len(dir) + 13:-2].replace('\', '/') 4 5 phyfiles = glob.glob('./live2D/' + str(dir) + '/**/*physics.json') 6 physics_vslue = str(phyfiles)[len(dir) + 13:-2].replace('\', '/') 7 8 mtnfiles = glob.glob('./live2D/' + str(dir) + '/**/*.mtn') 9 motions_idle_value = [{"file": str(mtn)[len(dir) + 10:].replace('\', '/')} for mtn in mtnfiles] 10 11 dic = { 12 "name": "Live2D", 13 "model": model_value, 14 "textures": [ 15 "Texture2D/texture_00.png" 16 ], 17 "motions": { 18 "idle": motions_idle_value, 19 "tap": [{"name": 0, "file": 0}]}, 20 "expressions": [{"name": 0, "file": 0}], 21 "physics": physics_value, 22 "lip_sync": "true" 23 } 24 ()

と構築するかな、と思いました。

投稿2020/03/03 07:27

編集2020/03/03 08:39
quickquip

総合スコア11038

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

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

退会済みユーザー

退会済みユーザー

2020/03/03 08:04

本文に追記しましたので参照してください.
quickquip

2020/03/03 08:44

globの順番はファイルシステムの影響を受けるので、格納順を保証するためには自分でソートする方がよい気がしましたが本筋ではないのでここに書いておくだけにします。
guest

0

ベストアンサー

ですが, "motions"以下のグループを書き出す際, Pythonの辞書配列では同階層に同じキーは存在することが出来ないため,

motions/idle の値は「各要素が {"file": <値>} のリスト」なので、同階層に同じキーが存在するという状況ではないと思います。

# 同階層に同じキーが存在するという状況ではない {"hoge": [{"fuga": "A"}, {"fuga": "B"}, {"fuga": "C"}]

python

1from pathlib import Path 2import json 3model = "XXX.moc" 4textures = ["XXX.png"] 5 6idle = [] 7for path in Path(r"sample").glob("*.mtn"): 8 idle.append({"file": str(path)}) 9 10 11j = { 12 "model": model, 13 "textures": textures, 14 "motions": {"idle": idle} 15} 16 17with open('output.json', 'w') as f: 18 json.dump(j, f, indent=4)

json

1{ 2 "model": "XXX.moc", 3 "textures": [ 4 "XXX.png" 5 ], 6 "motions": { 7 "idle": [ 8 { 9 "file": "sample\angry01.mtn" 10 }, 11 { 12 "file": "sample\angry02.mtn" 13 }, 14 { 15 "file": "sample\bye01.mtn" 16 } 17 ] 18 } 19}

投稿2020/03/03 08:14

編集2020/03/03 08:17
tiitoi

総合スコア21956

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

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

0

単に以下のようなコードでは駄目でしょうか
見当違いでしたらすいません

json

1{ 2 "model": "XXX.moc", 3 "textures": [ 4 "XXX.png" 5 ], 6 "motions": { 7 "idle": [ 8 { 9 "file": [ 10 "../motion/angry01.mtn", 11 "../motion/angry02.mtn", 12 "../motion/bye01.mtn", 13 "../motion/cry01.mtn", 14 "../motion/idle01.mtn", 15 "../motion/idle02.mtn", 16 "../motion/kime01.mtn", 17 "../motion/nf01.mtn", 18 "../motion/nf02.mtn", 19 "../motion/nf03.mtn", 20 "../motion/nf04.mtn", 21 "../motion/nf05.mtn", 22 "../motion/nf_left01.mtn", 23 "../motion/nf_right01.mtn", 24 "../motion/pui01.mtn", 25 "../motion/sad01.mtn", 26 "../motion/serious01.mtn", 27 "../motion/shame01.mtn", 28 "../motion/smile01.mtn", 29 "../motion/smile02.mtn", 30 "../motion/smile03.mtn", 31 "../motion/sneeze01.mtn", 32 "../motion/surprised01.mtn" 33 ] 34 } 35 ] 36 } 37}

投稿2020/03/03 07:25

super_hogehoge

総合スコア29

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

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

退会済みユーザー

退会済みユーザー

2020/03/03 07:28

すみません, 説明不足でした. 階層下げても駄目なんですよね... (ソフト側が読み込まない)
super_hogehoge

2020/03/03 07:38

「json形式」で「階層が無理」という状況がかなり特殊な気がします motion, idle, fileという情報が3つあるので階層化を強引に回避しようとするならば以下のような回避策しか思いつきません… { "model": "XXX.moc", "textures": [ "XXX.png" ], "motions_idle_file": [ "../motion/angry01.mtn", "../motion/angry02.mtn", "../motion/bye01.mtn", "../motion/cry01.mtn", "../motion/idle01.mtn", "../motion/idle02.mtn", "../motion/kime01.mtn", "../motion/nf01.mtn", "../motion/nf02.mtn", "../motion/nf03.mtn", "../motion/nf04.mtn", "../motion/nf05.mtn", "../motion/nf_left01.mtn", "../motion/nf_right01.mtn", "../motion/pui01.mtn", "../motion/sad01.mtn", "../motion/serious01.mtn", "../motion/shame01.mtn", "../motion/smile01.mtn", "../motion/smile02.mtn", "../motion/smile03.mtn", "../motion/sneeze01.mtn", "../motion/surprised01.mtn" ] }
退会済みユーザー

退会済みユーザー

2020/03/03 07:44

すみません, また説明が不足していたようなので訂正するのですが, 専用ソフトによって決められた階層以外は無理という意味です... こちらに(公式ページの方の)サンプルがありますが, どうにもこのフォーマットに沿わないとダメみたいですね. http://live2d.pavostudio.com/doc/en-us/live2d/model-json-example/ (というか, この製品だけの問題でなく, Live2Dのモデルファイルの書き方がこれ統一らしいです. 正直大変不便... )
super_hogehoge

2020/03/03 07:49

あれ、すいません 上記の公式サイトで { "version": "1.0.0", "model": "haru.moc", "textures": [ "haru.1024/texture_00.png", "haru.1024/texture_01.png", "haru.1024/texture_02.png" ], "motions": { "idle": [ { "file": "motions/haru_idle_01.mtn" }, { "file": "motions/haru_idle_02.mtn" } ] } } とサンプルで書いてありますが この書き方では駄目ですか?
退会済みユーザー

退会済みユーザー

2020/03/03 08:03

{ "file": "motions/haru_idle_02.mtn" } ] } } の部分なんですけど, idleとtapグループのみで繋がないといけないんですよね...
super_hogehoge

2020/03/03 08:14

うーん 追記されたコードの exdic.update({"file":str(mtn)[len(dir)+10:].replace('\','/')}) 辺りを "file": "motions/haru_idle_01.mtn", "file": "motions/haru_idle_02.mtn", から { "file": "motions/haru_idle_01.mtn" },{ "file": "motions/haru_idle_02.mtn" } のように直すだけなのでほとんど修正は必要ない気がします こちらでコードを実行できないので申し訳ないのですが私ではこれ以上お手伝いできそうにありません がんばってください!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問