How to reduce an array of objects in Python?
Question:
Apologies for the vague question, I am new to Python (JavaScript dev) and trying to reduce an array of objects into an array with objects combined if they have a matching ID. I tried using the reduce
from functools
, however, I am running into a wall.
from functools import reduce
# Attempt
result = reduce((lambda x, y: x + y), [
{
"id": '111',
"error": "MissingError",
"message": "Missing data",
"type": "red",
},
{
"id": '111',
"error": "Warning",
"message": "Missing attribute",
"type": "red",
},
{
"id": '222',
"error": "MissingError",
"message": "Missing data",
"type": "yellow"
}
])
print('Result', result)
# Expected
expected = [
{
"id": '111',
"type": "red"
"messages": [
{
"error": "MissingError",
"message": "Missing data",
},
{
"error": "Warning",
"message": "Missing attribute",
}
]
},
{
"id": '222',
"type": "yellow"
"messages": [
{
"error": "MissingError",
"message": "Missing data",
}
]
},
]
In JS I would use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
Answers:
This is not a reducing operation, you’re grouping by the ID and then accumulating into a list.
from collections import defaultdict
grp = defaultdict(list)
for d in data:
d = d.copy()
grp[d.pop('id')].append(d)
result = [{'id': k, 'messages': v} for k, v in grp.items()]
All credit to timgeb for their answer; this is just a slightly modified version to handle the edit to the question.
from collections import defaultdict
grouped = defaultdict(list)
for item in data:
item = item.copy()
grouped[item.pop('id'), item.pop('type')].append(item)
result = [{'id': id_, 'type': type_, 'messages': messages}
for (id_, type_), messages in grouped.items()]
(id_
and type_
are named that way in order to avoid collisions with builtins.)
P.S. It is generally poor form to alter your question after one or more people have already satisfactorily answered its original version. However, since this is a pretty minor change, I figured I would post this.
Apologies for the vague question, I am new to Python (JavaScript dev) and trying to reduce an array of objects into an array with objects combined if they have a matching ID. I tried using the reduce
from functools
, however, I am running into a wall.
from functools import reduce
# Attempt
result = reduce((lambda x, y: x + y), [
{
"id": '111',
"error": "MissingError",
"message": "Missing data",
"type": "red",
},
{
"id": '111',
"error": "Warning",
"message": "Missing attribute",
"type": "red",
},
{
"id": '222',
"error": "MissingError",
"message": "Missing data",
"type": "yellow"
}
])
print('Result', result)
# Expected
expected = [
{
"id": '111',
"type": "red"
"messages": [
{
"error": "MissingError",
"message": "Missing data",
},
{
"error": "Warning",
"message": "Missing attribute",
}
]
},
{
"id": '222',
"type": "yellow"
"messages": [
{
"error": "MissingError",
"message": "Missing data",
}
]
},
]
In JS I would use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
This is not a reducing operation, you’re grouping by the ID and then accumulating into a list.
from collections import defaultdict
grp = defaultdict(list)
for d in data:
d = d.copy()
grp[d.pop('id')].append(d)
result = [{'id': k, 'messages': v} for k, v in grp.items()]
All credit to timgeb for their answer; this is just a slightly modified version to handle the edit to the question.
from collections import defaultdict
grouped = defaultdict(list)
for item in data:
item = item.copy()
grouped[item.pop('id'), item.pop('type')].append(item)
result = [{'id': id_, 'type': type_, 'messages': messages}
for (id_, type_), messages in grouped.items()]
(id_
and type_
are named that way in order to avoid collisions with builtins.)
P.S. It is generally poor form to alter your question after one or more people have already satisfactorily answered its original version. However, since this is a pretty minor change, I figured I would post this.