-1

I am newbie with Python and I am trying to solve this problem in a script.

I have 2 lists of dictionaries as follows:

en_list = [{'time': 840, 'text': "I want to introduce you to some\nvery wise kids that I've known,"}, 
           {'time': 5480, 'text': 'but first I want\nto introduce you to a camel.'}, 
           {'time': 8720, 'text': 'This is Cassie, a therapy camel\nvisiting one of our young patients'}, 
           {'time': 13000, 'text': 'in her room,'},
           {'time': 14920, 'text': 'which is pretty magical.'}]

fr_list = [{'time': 840, 'text': "Je veux vous présenter certains enfants\ntrès sages que j'ai rencontrés,"},
           {'time': 5480, 'text': 'mais je veux commencer\npar vous présenter un chameau.'},
           {'time': 8720, 'text': 'Voici Cassie, un chameau thérapeutique qui\nrend visite à une de nos jeunes patients'},
           {'time': 14920, 'text': 'ce qui est plutôt magique.'}]

I want to create a new list with only matching values of the 'time' key.

I came up with this, but apparently it doesn't take the time key into consideration although it works just fine if both lists are having the same number of dictionaries.

for i, m in enumerate(zip(en_list, fr_list), start=1):
    print(i, m[0], "=", m[1])

This prints out the following:

1 {'time': 840, 'text': "I want to introduce you to some\nvery wise kids that I've known,"} = {'time': 840, 'text': "Je veux vous présenter certains enfants\ntrès sages que j'ai rencontrés,"}
2 {'time': 5480, 'text': 'but first I want\nto introduce you to a camel.'} = {'time': 5480, 'text': 'mais je veux commencer\npar vous présenter un chameau.'}
3 {'time': 8720, 'text': 'This is Cassie, a therapy camel\nvisiting one of our young patients'} = {'time': 8720, 'text': 'Voici Cassie, un chameau thérapeutique qui\nrend visite à une de nos jeunes patients'}
4 {'time': 13000, 'text': 'in her room,'} = {'time': 14920, 'text': 'ce qui est plutôt magique.'}

As you can see, it wrongly mapped the English with 'time': 13000 to the French with 'time': 14920 although the English list has the correct text with the same time, but the code above ignored it.

The desired output should include all items with the matching value of 'time' key and ignore the non-matching items. How can I achieve this?

Thanks in advance for your support!

Prune
  • 76,765
  • 14
  • 60
  • 81
MZe
  • 148
  • 2
  • 5
  • 1
    Your code doesn't check the `time` value at all; instead, you match only on physical position within the list. You have to at least *try* matching the `time` values. If you get stuck, search on line for solutions in dict entries with the same key. – Prune Aug 20 '18 at 16:26

3 Answers3

1

Your solution, as you said, doesn't take the time values into consideration. To craft a working solution for this, we need to get the time values for each list, find out which ones they have in common, then filter the original lists based on common time values.

# Make set of time values for given list.
get_times = lambda l: {d['time'] for d in l}
# Intersection of sets
times_shared = get_times(en_list) & get_times(fr_list)

# Get dicts whose time value is shared.
get_shared = lambda l: [d for d in l if d['time'] in times_shared]

for i, m in enumerate(zip(get_shared(en_list), get_shared(fr_list)), start=1):
    print(i, m[0], '=', m[1])

Or you could convert the lists to dicts first (pairs of time: text), which makes it much more straightforward:

makedict = lambda l: {d['time']: d['text'] for d in l}
en_dict = makedict(en_list)
fr_dict = makedict(fr_list)

# Intersection
times_shared = set(en_dict) & set(fr_dict)

for i, time in enumerate(times_shared, start=1):
    print('%d %d %r = %r' % (i, time, en_dict[time], fr_dict[time]))

Update Jun 1 2020: My code above has some bad practice, like named lambdas and l as a variable name. Also I forgot to sort times_shared. I might rewrite the second solution like this:

en, fr = ({d['time']: d['text'] for d in lst} for lst in [en_list, fr_list])

# Intersection
times_shared = sorted(set(en) & set(fr))

for i, time in enumerate(times_shared, start=1):
    print('%d %d %r = %r' % (i, time, en[time], fr[time]))
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • Than you so much wjandrea for your support. This works perfectly fine and it gets all desired results perfectly. Thank you so much for your support. Apparently, I need to learn about lambda. It seems to be extremely useful. – MZe Aug 22 '18 at 21:28
  • @MZEID Welcome! I'm using lamdbas here instead of one-line functions, that's all. Lambdas are more useful for anonymous functions, like to sort a dict by its values: `sorted(dict.items(), key=lambda t: t[1])` – wjandrea Aug 22 '18 at 21:39
  • @MZe FYI it turns out named lambdas are bad practice. Check out my updated solution. – wjandrea Jun 01 '20 at 17:34
  • 1
    Thanks a million for updating the answer and for keeping me posted about it. I really appreciate it. Thanks! – MZe Jun 06 '20 at 17:44
0

Make a list from each dict, including all of the time values. Find the times common to both lists (making another list). Iterate through this list of common times, printing the corresponding dict from each of your two lists.

Each of these steps is a common programming technique covered in tutorials and other Stack Overflow questions. Coding is left as an exercise for the student.

Prune
  • 76,765
  • 14
  • 60
  • 81
0
list(filter(lambda item: item[0].get('time') == item[1].get('time'), zip(en_list, fr_list)))

(EDITED): Maybe this will work

result = []
for k, en in enumerate(en_list):
    for fr in fr_list:
        if en.get('time') == fr.get('time'):
            result.append({k: '{} = {}'.format(en, fr)})
Higor Rossato
  • 1,996
  • 1
  • 10
  • 15
  • This only works if the same times are at the same position in the lists, which they're not. Time 14920 is excluded from the output. – wjandrea Aug 20 '18 at 16:52
  • 1
    Thank you so much Higor for your help with this. This works perfectly fine for the example above, but it seems it stops looping once it hits a not-matching key value. If the 2 lists have the same exact number of dictionaries, it gets them all perfectly, but if there is a mismatch, it stops looping. Is there a way to make it keep looping and just ignore the non-matching values? Thanks again for your kind support. – MZe Aug 20 '18 at 16:58
  • Thanks again Higor for taking the time to support. Your solution's logic works perfectly fine and it gets the correct result, but for some reason, the printed out strings are full of back slashes. Not sure why though, but thanks a million for your support. – MZe Aug 22 '18 at 21:26