1

I am quite new to python and development in general, so I am sure that my question is phrased a little bit wrong. English is also not my first language, so if you're looking for more info about what I want to do, I will be happy to explain.

Basically, I have a list of dictionaries, where they all share the same keys but different values. For example:

List1 =  [{
'name':'yuval',
'age':16,
'favorite_thing_to_do': 'playing the cello' },

{
'name':'yuval',
'age':16,
'favorite_thing_to_do':'hearing music'},
'name':'shiri',
'age':12,
'favorite_thing_to_do':'watch TV'}]

The output I am looking for is a list where favorite_thing_to_do is merged wherever it can.

For example, the out will be

[{'name':'yuval',
'age':16,
'favorite_thing_to_do': ['playing the cello' , 'hearing music']},

{'name':'shiri',
'age':12,
'favorite_thing_to_do':'watch TV'}]

However, I can't wrap my head about how to do it. I managed to define a function called merge_dict , which basically takes two dictionaries, compares the first two keys (name and age) and if the values are the same, it returns a dictionary where favorite_thing_to_do is a list of the different values in the two different dictionaries that the function received.

As a concept, the function works great; However, I don't know how to run this function over a list with 100+ unfiltered dictionaries; Is there a simpler way to do it?

EDIT: I am going to include the relevant code I have done so far. I have no idea how to do what I want within a list, so I just declared two dictionaries: Item3, Item4 which my function merge_dict concentrated:

Item3 = {
'name':'shiri',
'age':12,
'favorite_thing_to_do':'watch TV'}

Item4 = {
'name':'shiri',
'age':12,
'favorite_thing_to_do': 'listening to teachers'

 }

def merge_dict(dict1, dict2):
# we know that dict1 and dict2 are the same length, same keys.
    dict3 = {}

    for i in dict1:
        if dict1[i] == dict2[i]:
            dict3[i] = dict1[i]

    if i == 'favorite_thing_to_do':
        if isinstance(dict1[i], str) and isinstance(dict2[i],str) :
            dict3[i] = [dict1[i] , dict2[i]]

        if isinstance(dict1[i], list) and isinstance(dict2[i],str):
            dict3[i] = dict1[i] + [dict2[i]]

        if isinstance(dict1[i], str) and isinstance(dict2[i],list):
            dict3[i] = [dict1[i]] + dict1[i]

        if isinstance(dict1[i], list) and isinstance(dict2[i],list):
            dict3[i] = dict1[i] + dict1[i]

return dict3


print(merge_dict(Item3, Item4))
>>> {'name': 'shiri', 'age': 12, 'favorite_thing_to_do': ['watch TV', 
'listening to teachers']}
yuvalhad12
  • 23
  • 4

2 Answers2

0

I see that I have missed the name and age part. This is a variant in which I have used a tuple of name and age as a key and a dict as a value.

Edited to show the result in the asked format (though it might be better to just return names):

def merge(dirs):
    names = {}
    for d in dirs:
        if (d['name'], d['age']) not in names:
            names[(d['name'], d['age'])] = {}
        for k in d:
            if k not in ('name', 'age'):
                if k not in names[(d['name'], d['age'])]:
                    names[(d['name'], d['age'])][k] = set([])
                names[(d['name'], d['age'])][k].add(d[k])
  # return names
    return [{'name':k[0], 'age':k[1], 'favorite_things_to_do': 
         list(v2) } for k, v in names.items() for v2 in v.values() ]

print(merge(List1))
Marko
  • 372
  • 2
  • 7
  • Thanks for the answer! I tested it and it seems to mostly work. Just a heads up, if someone's going to use it in the future, when you declare result[k] = list(result[k]), it can lead to a list with only one value. Therefore I added an if statement - "if len(result[k]) == 1:result[k] = result[k][0]". That seems to fix the issue of lists with length of one, which makes the code look prettier and more clear. – yuvalhad12 Aug 29 '20 at 09:03
0

You can do with something like that:

List1 =  [{
'name':'yuval',
'age':16,
'favorite_thing_to_do': 'playing the cello' },
{
'name':'yuval',
'age':16,
'favorite_thing_to_do':'hearing music'},
{'name':'shiri',
'age':12,
'favorite_thing_to_do':'watch TV'}]


def merge_dict(dictionary,merged_dict):
    name = dictionary.get('name')
    age = dictionary.get('age')
    favorite = dictionary.get('favorite_thing_to_do')

    #var to inform if needed to write a new dict:
    found_item = False

    # if merged_dict list is empty create the first dict:
    if len(merged_dict)==0:
        merged_dict.append({'name':name, 'age':age,'favorite_thing_to_do':[favorite] })

    # if  merged_dict list is not empty,
    else:
        #look for name and age in all dicts of merged_dict:
        for registred_dict in merged_dict:
            #If found => Append favorite_thing_to_do
            if registred_dict.get('name') == name and registred_dict.get('age')==age:
                registred_dict['favorite_thing_to_do'].append(favorite)
                found_item=True

        #If not found create a new dict in merged_dict:
        if not found_item:
            merged_dict.append({'name':name, 'age':age,'favorite_thing_to_do':[favorite] })


merged_dict = []
for dictionary in List1:
    merge_dict(dictionary,merged_dict)
print(merged_dict)

Item4 = {
'name':'shiri',
'age':12,
'favorite_thing_to_do': 'listening to teachers'
 }
merge_dict(Item4,merged_dict)
print(merged_dict)

Result first print:

[{'name': 'yuval', 'age': 16, 'favorite_thing_to_do': ['playing the cello', 'hearing music']}, {'name': 'shiri', 'age': 12, 'favorite_thing_to_do': ['watch TV']}]

Result after merged Item4:

[{'name': 'yuval', 'age': 16, 'favorite_thing_to_do': ['playing the cello', 'hearing music']}, {'name': 'shiri', 'age': 12, 'favorite_thing_to_do': ['watch TV', 'listening to teachers']}]
Renaud
  • 2,709
  • 2
  • 9
  • 24