Merging a list of dictionaries - list

I have a list of dicts as below.
list = [ {id: 1, s_id:2, class: 'a', teacher: 'b'} ]
list1 = [ {id: 1, c_id:1, rank:2, area: 34}, {id:1, c_id:2, rank:1, area: 21} ]
I want to merge the two lists on the common key-value pairs (in this case 'id:1')
Merged_list = [ {id:1, s_id:2, class: 'a', teacher: 'b', list1: {c_id:1, rank: 2, area: 34}, {c_id:2, rank: 1, area: 21} ]
How do I go about this?
Thanks

You can use
merged_list = [{**d1, **d2} for d1, d2 in zip(list1, list2)]
>>> merged_list
[{'id': 1, 's_id': 2, 'class': 'a', 'teacher': 'b', 'rank': 2, 'area': 34},
{'id': 2, 's_id': 3, 'class': 'c', 'teacher': 'd', 'rank': 1, 'area': 21}]
where {**d1, **d2} is just a neat way to combine 2 dictionaries. Keep in mind this will replace the duplicate keys of the first dictionary. If you're on Python 3.9, you could use d1 | d2.
EDIT: For the edit in your question, you can try this horrible one liner (keep in mind this will create the pair list1: [] if no matching indeces were found on list1):
list_ = [{"id": 1, "s_id": 2, "class": 'a', "teacher": 'b'}]
list1 = [{"id": 1, "c_id": 1, "rank": 2, "area": 34}, {"id": 1, "c_id": 2, "rank": 1, "area": 21}]
merged_list = [{**d, **{"list1": [{k: v for k, v in d1.items() if k != "id"} for d1 in list1 if d1["id"] == d["id"]]}} for d in list_]
>>> merged_list
[{'id': 1,
's_id': 2,
'class': 'a',
'teacher': 'b',
'list1': [{'c_id': 1, 'rank': 2, 'area': 34},
{'c_id': 2, 'rank': 1, 'area': 21}]}]
This is equivalent to (with some added benefits):
merged_list = []
for d in list_:
matched_ids = []
for d1 in list1:
if d["id"] == d1["id"]:
d1.pop("id") # remove id from dictionary before appending
matched_ids.append(d1)
if matched_ids: # added benefit of not showing the 'list1' key if matched_ids is empty
found = {"list1": matched_ids}
else:
found = {}
merged_list.append({**d, **found})

Try this
And don't forget to put " " when declare string
list = [ {"id": 1, "s_id": 2 ," class": 'a', "teacher": 'b'}, {"id": 2, "s_id" : 3, "class" : 'c', "teacher": 'd'} ]
list1 = [ {"id": 1, "rank" :2, "area" : 34}, {"id" :2, "rank" :1, "area": 21} ]
list2 = list1 + list
print(list2)

Related

How does Django query the tree structure

I am new to Django and I am creating a blog and comment function
from django.db import models
from django.contrib.auth import get_user_model
class Blog(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
title = models.CharField(max_length=200)
content = models.TextField(max_length=200)
class Comment(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name="children")
content = models.CharField(max_length=200)
This is my current test data
Comment.objects.all().values()
<QuerySet [
{'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1'},
{'id': 2, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '2'},
{'id': 3, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-1'},
{'id': 4, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-2'}
]>
But now I want to find out such a tree structure, what should I do?
[
{'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1', 'children': [
{'id': 3, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-1'},
{'id': 4, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-2'}
]},
{'id': 2, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '2', 'children': [] },
]
You can' t obtain a nested dictionary with values.
You could write this:
Comment.objects.all().values('id', 'user_id', 'blog_id', 'parent_id', 'content', 'children')
But the result will not be as you expected, the list will contain a dict for every parent-child combination, for example:
[
{'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1', children: 2},
{'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1', children: 3},
{'id': 2, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '2', children: None},
{'id': 3, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '2', children: None},
]
You can deal directly with the queryset, for example:
for comment in Comment.objects.all().prefetch_related('children'):
for child in comment.children.all():
print(child.id)
Or you can use a nested list comprehension (the result will be as you expected):
print([{'id': comment.id, 'user_id': comment.user.id, 'blog_id': comment.blog.id, 'parent_id': comment.parent.id if comment.parent != None else None, 'content': comment.content, 'children': [{'id':
child.id, 'user_id': child.user.id, 'blog_id': child.blog.id, 'parent_id': child.parent.id, 'content': child.content} for child in comment.children.all()]} for comment in Comment.objects.all()])
I use recursion to query
def get_children(c):
return {
'id': c.id,
'user_id': c.user_id,
'blog_id': c.blog_id,
'parent_id': c.parent_id,
'content': c.content,
'children': list(map(get_children, c.children.all())),
}
def get_comment_tree():
return list(map(get_children, Comment.objects.filter(parent=None).prefetch_related('children')))
Output json
[{
"id": 1,
"user_id": 1,
"blog_id": 1,
"parent_id": null,
"content": "1",
"children": [{
"id": 3,
"user_id": 1,
"blog_id": 1,
"parent_id": 1,
"content": "1-1",
"children": [{
"id": 5,
"user_id": 1,
"blog_id": 1,
"parent_id": 3,
"content": "1-1-1",
"children": []
}]
}, {
"id": 4,
"user_id": 1,
"blog_id": 1,
"parent_id": 1,
"content": "1-2",
"children": []
}]
}, {
"id": 2,
"user_id": 1,
"blog_id": 1,
"parent_id": null,
"content": "2",
"children": []
}]

Remove elements from List that are missing in another list

I would like to remove from List a elements that are not in another List. Suppose I have
List a = [{"id": 1}, {"id": 2}, {"id": 4}, {"id": 7},]
List b = [{"id": 1}, {"id": 2}, {"id": 7},]
Then I would like to remove from List a the element {"id": 4}, since it is missing in List b
If List b were
List b = [{"id": 1}, {"id": 2}, {"id": 4},]
then I would like to remove from List a element {"id": 7}
How to do this in Flutter.
Thank you.
void main() {
var a = [{"id": 1}, {"id": 2}, {"id": 4}, {"id": 7}];
var b = [{"id": 1}, {"id": 2}, {"id": 7}];
var c = a.map((m) => m['id']);
var d = b.map((m) => m['id']);
var e = c.toSet().difference(d.toSet());
var f = a.where((m) => e.contains(m['id']));
print(f);
}
Result
({id: 4})
I fixed it like this
List a = [{"id": 1}, {"id": 2}, {"id": 4}, {"id": 7}];
List b = [{"id": 1}, {"id": 2}, {"id": 7}];
a.removeWhere((elementA) => b.every((elementB) =>
elementB["id"] != elementA["id"]));

Django ORM queryset equivalent to group by year-month?

I have an Django app and need some datavisualization and I am blocked with ORM.
I have a models Orders with a field created_at and I want to present data with a diagram bar (number / year-month) in a dashboard template.
So I need to aggregate/annotate data from my model but did find a complete solution.
I find partial answer with TruncMonth and read about serializers but wonder if there is a simpliest solution with Django ORM possibilities...
In Postgresql it would be:
SELECT date_trunc('month',created_at), count(order_id) FROM "Orders" GROUP BY date_trunc('month',created_at) ORDER BY date_trunc('month',created_at);
"2021-01-01 00:00:00+01" "2"
"2021-02-01 00:00:00+01" "3"
"2021-03-01 00:00:00+01" "3"
...
example
1 "2021-01-04 07:42:03+01"
2 "2021-01-24 13:59:44+01"
3 "2021-02-06 03:29:11+01"
4 "2021-02-06 08:21:15+01"
5 "2021-02-13 10:38:36+01"
6 "2021-03-01 12:52:22+01"
7 "2021-03-06 08:04:28+01"
8 "2021-03-11 16:58:56+01"
9 "2022-03-25 21:40:10+01"
10 "2022-04-04 02:12:29+02"
11 "2022-04-13 08:24:23+02"
12 "2022-05-08 06:48:25+02"
13 "2022-05-19 15:40:12+02"
14 "2022-06-01 11:29:36+02"
15 "2022-06-05 02:15:05+02"
16 "2022-06-05 03:08:22+02"
expected result
[
{
"year-month": "2021-01",
"number" : 2
},
{
"year-month": "2021-03",
"number" : 3
},
{
"year-month": "2021-03",
"number" : 3
},
{
"year-month": "2021-03",
"number" : 1
},
{
"year-month": "2021-04",
"number" : 2
},
{
"year-month": "2021-05",
"number" : 3
},
{
"year-month": "2021-06",
"number" : 3
},
]
I have done this but I am not able to order by date:
Orders.objects.annotate(month=TruncMonth('created_at')).values('month').annotate(number=Count('order_id')).values('month', 'number').order_by()
<SafeDeleteQueryset [
{'month': datetime.datetime(2022, 3, 1, 0, 0, tzinfo=<UTC>), 'number': 4},
{'month': datetime.datetime(2022, 6, 1, 0, 0, tzinfo=<UTC>), 'number': 2},
{'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=<UTC>), 'number': 1},
{'month': datetime.datetime(2022, 1, 1, 0, 0, tzinfo=<UTC>), 'number': 5},
{'month': datetime.datetime(2021, 12, 1, 0, 0, tzinfo=<UTC>), 'number': 1},
{'month': datetime.datetime(2022, 7, 1, 0, 0, tzinfo=<UTC>), 'number': 1},
{'month': datetime.datetime(2021, 9, 1, 0, 0, tzinfo=<UTC>), 'number': 2},
'...(remaining elements truncated)...'
]>
Try adding the order_by on the original field if you have multi-year data.
from django.db.models import Sum
from django.db.models.functions import TruncMonth
Orders.objects.values(month=TruncMonth('created_at')).
order_by("created_at").annotate(Sum('number')

how to count number of occurrences of element in list of maps in dart?

I have a list of maps like this
data = [
{
'id': 100,
'quantity': 20
},
{
'id': 101,
'quantity': 25
},
{
'id': 101,
'quantity': 30
}
{
'id': 105,
'quantity': 50
}
]
I am able to count occurrences of element in a list like this
data.forEach((x) => map[x] = !map.containsValue(x) ? (1) : (map[x] + 1));
print(map);
Output :
{{id: 100, quantity: 20}: 1, {id: 101, quantity: 25}: 1, {id: 101, quantity: 30}: 1, {id: 105, quantity: 50}: 1}
But I want to count how many times id = 101 comes in the list so How can I achieve that?
You can use where to filter your array of maps and then use the getter length :
var data = [
{'id': 100, 'quantity': 20},
{'id': 101, 'quantity': 25},
{'id': 101, 'quantity': 30},
{'id': 105, 'quantity': 50}
];
print(data.where((e) => e['id'] == 101).length); // 2

what is the easiest way to merge 2 list of object in flutter dart?

what is the easiest way to merge 2 list of object in flutter dart and achieve the result?
List 1
[
{name: eat, frequency: Daily},
{name: read, frequency: Daily},
{name: walk, frequency: Daily,}
]
List 2
[
{name: eat, count: 2},
{name: read, count: 2},
{name: walk, count: 2,}
]
Result
[
{name: eat, count: 2, frequency: Daily},
{name: read, count: 2, frequency: Daily},
{name: walk, count: 2, frequency: Daily}
]
Assuming the lists have the same length and contain Maps:
void main() {
var l1 = [
{'name': 'eat', 'frequency': 'Daily'},
{'name': 'read', 'frequency': 'Daily'},
{'name': 'walk', 'frequency': 'Daily'}
];
var l2 = [
{'name': 'eat', 'count': 2},
{'name': 'read', 'count': 2},
{'name': 'walk', 'count': 2}
];
var l3 = [
for (var i = 0; i < l1.length; i++) {...l1[i], ...l2[i]},
];
print(l3);
// [{name: eat, frequency: Daily, count: 2}, {name: read, frequency: Daily, count: 2}, {name: walk, frequency: Daily, count: 2}]
}
There are several simple ways to combine these lists, but they run into several issues. For example, can you guarantee that the lists will be the same length and that the order of the lists will be identical (as far as the "name" field in the nested maps are concerned)?
If you can't guarantee equal length and matching order, then you need to resort to a slightly more complex approach that is agnostic to either of those issues.
void main() {
final list1 = [
{'name': 'eat', 'frequency': 'Daily'},
{'name': 'read', 'frequency': 'Weekly'},
{'name': 'walk', 'frequency': 'Monthly'},
];
final list2 = [
{'name': 'walk', 'count': 4},
{'name': 'eat', 'count': 2},
{'name': 'read', 'count': 3},
];
// Convert the second list into a lookup table
final lookup = Map.fromIterable(list2, key: (m) => m['name'], value: (m) => m);
// Generate the combined list, using the first list as a base
final combined = list1.map((m) => { ...m, ...lookup[m['name']] }).toList();
print(combined);
// Prints (formatted)
// [
// {name: eat, count: 2, frequency: Daily},
// {name: read, count: 3, frequency: Weekly}
// {name: walk, count: 4, frequency: Monthly},
// ]
}