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

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

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

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

Q&A

解決済

4回答

517閲覧

リストの形を変更したい

sasaki0628

総合スコア106

Python 3.x

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

0グッド

0クリップ

投稿2023/01/13 01:01

編集2023/01/13 03:17

リスト型のデータを以下のように変更したいと思っています。

変更前データ

[ { "id": 1, "fruits": "apple", "cd": 1 }, { "id": 1, "fruits": "apple", "cd": 2 }, { "id": 1, "fruits": "apple", "cd": 4 }, { "id": 2, "fruits": "banana", "cd": 5 }, { "id": 3, "fruits": "grape", "cd": 3 }, { "id": 3, "fruits": "grape", "cd": 6 }, { "id": 3, "fruits": "grape", "cd": 7 }, ]

変更後イメージ

[ { "id": 1, "fruits": "apple", "cd": [1,2,4] }, { "id": 2, "fruits": "banana", "cd": [5] }, { "id": 3, "fruits": "grape", "cd": [3,6,7] } ]

以下のコードを作成し、実行しました。

list = [ { "id": 1, "fruits": "apple", "cd": 1 }, { "id": 1, "fruits": "apple", "cd": 2 }, { "id": 1, "fruits": "apple", "cd": 4 }, { "id": 2, "fruits": "banana", "cd": 5 }, { "id": 3, "fruits": "grape", "cd": 3 }, { "id": 3, "fruits": "grape", "cd": 6 }, { "id": 3, "fruits": "grape", "cd": 7 }, ] id_1 = 0 # 初期値 j = 0 # 初期値 e = [] for item in list: id_2 = item["id"] if id_1 == id_2: cd_1.append(item["cd"]) item["cd"] = cd_1 e.append(j - 1) else: id_1 = item["id"] item["cd"] = [item["cd"]] cd_1 = item["cd"] j += 1 j = 0 # 初期値 k = 0 # 初期値 for _ in e: del list[e[j] - k] j += 1 k += 1

実行結果

>>> list [{'id': 1, 'fruits': 'apple', 'cd': [1, 2, 4]}, {'id': 2, 'fruits': 'banana', 'cd': [5]}, {'id': 3, 'fruits': 'grape', 'cd': [3, 6, 7]}]

【コードの流れ】

  1. 変数 list にデータを格納する。
  2. 変数 id_1 の初期値を 0 にする。
  3. リスト型の変数 e を用意する。
  4. list の各データに対して、id の値と id_1 の値を比較する。

4-1. id の値と id_1 の値が異なるならば(if文のelseの処理)1つ目のデータと判断し、id_1 の値を更新する。cd の値をリスト型に変更する。cd_1 というリスト型の変数に cd の値を代入する。
4-2. id の値と id_1 の値値が同じならば、2つ目以降のデータと判断する。cd_1 に cd の値を append する。cd_1 の変数を更新する。リストe にひとつ前のリスト番号を格納する。
5. リストeには不要なデータのリスト番号が格納されている。変数listに対して、不要なデータの削除を実行する。

可読性が低いコードになっています。より良く書けるコードがあれば教えていただきたいです。

▽追記
みなさま回答ありがとうございました。自分の実力ではどれをベストアンサーにすればよいかわからないので、1ヵ月ほど様子を見て「グッド」の数が多い回答をベストアンサーにして質問を閉めさせていただきます。ありがとうございました。

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

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

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

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

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

melian

2023/01/13 01:22

else:  id_1 = item["id"]  cd_1 = [item["cd"]] => else:  id_1 = item["id"]  cd_1 = [item["cd"]]  item["cd"] = cd_1
sasaki0628

2023/01/13 01:34

コメントありがとうございます。申し訳ございません、質問投稿後、修正箇所に気付き、質問内容そのものを変更いたしました。質問内容を変更している途中でコメントをいただきました。
guest

回答4

0

元のリストの変数名を data とします。(listだとPythonに組み込みのlistと被るためです)

python

1data = [ 2 { 3 "id": 1, 4 "fruits": "apple", 5 "cd": 1 6 }, 7 { 8 "id": 1, 9 "fruits": "apple", 10 "cd": 2 11 }, 12 { 13 "id": 1, 14 "fruits": "apple", 15 "cd": 4 16 }, 17 { 18 "id": 2, 19 "fruits": "banana", 20 "cd": 5 21 }, 22 { 23 "id": 3, 24 "fruits": "grape", 25 "cd": 3 26 }, 27 { 28 "id": 3, 29 "fruits": "grape", 30 "cd": 6 31 }, 32 { 33 "id": 3, 34 "fruits": "grape", 35 "cd": 7 36 }, 37]

以下は上記のdataから質問にある「変更後イメージ」のリストをresultとして得るコード例です。(functools.reduce と itertools.groupby を使用しました。)

python

1from functools import reduce 2from itertools import groupby 3 4 5result = [ 6 reduce(lambda acc, e: acc['cd'].append(e['cd']) or acc, group, {'id': k[0], 'fruits': k[1], 'cd':[]}) 7 for k, group 8 in groupby(data, lambda e: (e['id'], e['fruits'])) 9] 10 11print(result) # => [{'id': 1, 'fruits': 'apple', 'cd': [1, 2, 4]}, {'id': 2, 'fruits': 'banana', 'cd': [5]}, {'id': 3, 'fruits': 'grape', 'cd': [3, 6, 7]}]

追記

resultの要素を作るためにreduceは不要でした。以下でも目的のリストを得られます。

python

1from itertools import groupby 2 3 4result = [ 5 {'id': k[0], 'fruits': k[1], 'cd': [e['cd'] for e in group]} 6 for k, group 7 in groupby(data, lambda e: (e['id'], e['fruits'])) 8]

投稿2023/01/13 02:44

編集2023/01/13 03:27
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

sasaki0628

2023/01/15 05:49

回答ありがとうございます。シンプルでわかりやすいです。
guest

0

ベストアンサー

itertools の groupby を使う方法です。

python

1from itertools import groupby 2 3lst = [ 4 { 5 "id": 1, 6 "fruits": "apple", 7 "cd": 1 8 }, 9 { 10 "id": 1, 11 "fruits": "apple", 12 "cd": 2 13 }, 14 { 15 "id": 1, 16 "fruits": "apple", 17 "cd": 4 18 }, 19 { 20 "id": 2, 21 "fruits": "banana", 22 "cd": 5 23 }, 24 { 25 "id": 3, 26 "fruits": "grape", 27 "cd": 3 28 }, 29 { 30 "id": 3, 31 "fruits": "grape", 32 "cd": 6 33 }, 34 { 35 "id": 3, 36 "fruits": "grape", 37 "cd": 7 38 }, 39] 40 41# 42result = [] 43keyfunc = lambda x: x['id'] 44for k, g in groupby(sorted(lst, key=keyfunc), keyfunc): 45 g = list(g) 46 result.append({'id': k, 'fruits': g[0]['fruits'], 'cd': [i['cd'] for i in g]}) 47 48print(result) 49 50# [{'id': 1, 'fruits': 'apple', 'cd': [1, 2, 4]}, {'id': 2, 'fruits': 'banana', 'cd': [5]}, {'id': 3, 'fruits': 'grape', 'cd': [3, 6, 7]}]

投稿2023/01/13 01:46

melian

総合スコア19714

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

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

sasaki0628

2023/01/15 05:49

回答ありがとうございます。itertools.groupbyを知りませんでした。勉強になります。
guest

0

まずはidをキーとした辞書に要素を集めて、その辞書からリストを再作成すると簡潔にできると思います。

Python

1lst = [{'id': 1, 'fruits': 'apple', 'cd': 1}, 2 {'id': 1, 'fruits': 'apple', 'cd': 2}, 3 {'id': 1, 'fruits': 'apple', 'cd': 4}, 4 {'id': 2, 'fruits': 'banana', 'cd': 5}, 5 {'id': 3, 'fruits': 'grape', 'cd': 3}, 6 {'id': 3, 'fruits': 'grape', 'cd': 6}, 7 {'id': 3, 'fruits': 'grape', 'cd': 7}] 8 9items = dict() 10for item in lst: 11 i = item['id'] 12 # まだ存在しなければ要素を追加 13 if i not in items: 14 items[i] = {'fruits':item['fruits'], 'cd':[]} 15 items[i]['cd'].append(item['cd']) # cdをリストに追加 16 17ret = [{'id':key, 'fruits':val['fruits'], 'cd':val['cd']} for key, val in items.items()] 18print(ret) 19# [{'id': 1, 'fruits': 'apple', 'cd': [1, 2, 4]}, 20# {'id': 2, 'fruits': 'banana', 'cd': [5]}, 21# {'id': 3, 'fruits': 'grape', 'cd': [3, 6, 7]}]

投稿2023/01/13 01:35

can110

総合スコア38262

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

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

sasaki0628

2023/01/15 05:49

回答ありがとうございます。非常に勉強になりました。
guest

0

cdが1つだけのとき、list内のアイテムの更新が行なわれないからです。

python

1for item in list: 2 id_2 = item["id"] 3 if id_1 == id_2: 4 cd_1.append(item["cd"]) 5 item["cd"] = cd_1 # 2つめ以降は更新している 6 e.append(j - 1) 7 else: 8 id_1 = item["id"] 9 cd_1 = [item["cd"]] # 1つだけのときは、 cd_1 に入れているだけ。 10 item["cd"] = cd_1 # ★これを追加すればいいのではないかと 11 j += 1

いくつかコメントします。

listという変数は関数listと名前が衝突しますので、別の名前にしたすべきと思います。

listの変更が目的ということからか、変更後に不要な項目を削除するというロジックになっていますが、最初のループで新規のリストを作り必要であれば最後に置き換えるほうがわかりやすい処理になると思います。また、そうすることで、集計する時のロジックもすっきりしたものにできると思います。


追記

こんな感じで。 idをキーとした辞書を作る案は出ていて基本同じですが、 id と fruits のタプルをキーにして辞書を作ってみました。

python

1result_dict = {} 2 3for item in item_list: 4 item_key = (item['id'], item['fruits']) 5 cd_list = result_dict.get(item_key, []) 6 cd_list.append(item['cd']) 7 result_dict[item_key] = cd_list 8 9new_list = [] 10for item in result_dict: 11 new_list.append({"id": item[0], 12 "fruits": item[1], 13 "cd": result_dict[item]} 14 )

投稿2023/01/13 01:24

編集2023/01/13 02:11
TakaiY

総合スコア12747

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

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

sasaki0628

2023/01/13 01:32 編集

回答ありがとうございます。申し訳ございません、質問投稿後、修正箇所に気付き、質問内容そのものを変更いたしました。質問内容を変更している途中で回答をいただきました。
sasaki0628

2023/01/15 05:48

回答ありがとうございます。とても読みやすいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問