1

I have 2 dictionary lists which has the same key, but different values.

Dict_one = {"A": ["a1", "a2", "a3"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c4"]}

Dict_two = {"A": ["a1"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c5"]}

I want to get 2 dictionary lists;

One is the dictionary list of values in Dict_one but not in Dict_two.

The other is the dictionary list of values in Dict_two but not in Dict_one.

Result example:

Result_one_two = {"A": ["a2", "a3"], "B": [], "C": ["c4"]}
Result_two_one = {"A": [], "B": [], "C": ["c5"]}

What is the most pythonic way to get the output?

Edit: They always have the same keys.

Will Moon
  • 21
  • 3

6 Answers6

2

You can use set.difference within a dict comprehension:

In [29]: Result_one_two = {k: set(Dict_one[k]).difference(Dict_two[k]) for k in Dict_one}

In [30]: Result_one_two
Out[30]: {'A': {'a2', 'a3'}, 'B': set(), 'C': {'c4'}}

In [31]: Result_two_one = {k: set(Dict_two[k]).difference(Dict_one[k]) for k in Dict_one}

In [32]: Result_two_one
Out[32]: {'A': set(), 'B': set(), 'C': {'c5'}}

It's better to preserve the values as set at the first place tho. In that case you won't need to call the set for each value. Also note that if you're using Python-3.6+ since dictionaries in these versions are insertion ordered the output will be as expected, otherwise you should use an OrderedDict to keep track of orders. But if the performance is not an issue here and/or you're dealing with a short data set you can just use a list comprehension as is explained in other answers.

Also, as mentioned in comments, if the order of values is important for you in order to take advantage of set operations and yet keep the order you can use a custom ordered set like what's proposed here https://stackoverflow.com/a/10006674/2867928 by Raymond Hettinger.

Mazdak
  • 105,000
  • 18
  • 159
  • 188
  • 1
    Is order important? Probably best to clarify the poor question before leaping in with a wrong answer. – Peter Wood Jun 26 '18 at 05:52
  • @PeterWood I didn't find anything regard the importance of order in question, however I updated the answer with some extra info regard that matter. Besides, if you think this answer is wrong please explain the reasons in details and downvote my answer. – Mazdak Jun 26 '18 at 05:59
  • I'm not talking about dictionary key order. The question has lists as values, the sets could change the order. – Peter Wood Jun 26 '18 at 07:05
  • Really appreciate your help. Thanks. – Will Moon Jun 26 '18 at 07:06
  • @Kasramvd my time is not free `#happytohelp` – Peter Wood Jun 26 '18 at 07:21
  • @PeterWood Well in that case you're better to not let your words be for free too because words by themselves are obscure and their meanings are more often subjective. Now imagine what happens when you echo that effect by not using them in an elaborated manner. – Mazdak Jun 26 '18 at 07:26
  • @Kasramvd I've obviously touched a nerve, apologies. – Peter Wood Jun 26 '18 at 07:32
  • @PeterWood Not at all. Discussion! That's what separates us from the rest of the world (at least this is what we think proudly ;)) ). – Mazdak Jun 26 '18 at 07:34
1

You can do so:

Result_one_two = {
    k: [v for v in vals if v not in Dict_two.get(k, [])]
    for k, vals in Dict_one.items()
}

Output:

Result_one_two = {'A': ['a2', 'a3'], 'C': ['c4'], 'B': []}

And second one:

Result_two_one = {
    k: [v for v in vals if v not in Dict_one.get(k, [])]
    for k, vals in Dict_two.items()
}

Output:

Result_two_one = {'A': [], 'C': ['c5'], 'B': []}
Joe
  • 12,057
  • 5
  • 39
  • 55
1

I hope this code will help you

#first one:
dict_one = {"a":["a1","a2","a3"], "b": ["b1","b2"], "c":["c1","c2","c3","c4"]}
dict_two = {"a": ["a1"], "b":["b1","b2"], "c": ["c1","c2","c3","c5"]}
dict_end = {}
dict_end2 = {}
for i in dict_one:
  for j in (dict_one[i]):
    if j not in dict_two[i]:
      dict_end[i] = j

print (dict_end)
#second one goes below : 
for i in dict_two:
  for j in (dict_two[i]):
    if j not in dict_one[i]:
      dict_end2[i] = j

print (dict_end2)
M. Ali Öztürk
  • 332
  • 1
  • 2
  • 11
0
Dict_one = {"A": ["a1", "a2", "a3"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c4"]}
Dict_two = {"A": ["a1"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c5"]}

dict(map(lambda k: (k, list(set(Dict_one[k]) - set(Dict_two.get(k, [])))), Dict_one))
# {'A': ['a2', 'a3'], 'B': [], 'C': ['c4']}

dict(map(lambda k: (k, list(set(Dict_two.get(k, [])) - set(Dict_one[k]))), Dict_one))
# {'A': [], 'B': [], 'C': ['c5']}
Sunitha
  • 11,777
  • 2
  • 20
  • 23
0

Similar to @kasramvd

Dict_one = {"A": ["a1", "a2", "a3"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c4"]}
Dict_two = {"A": ["a1"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c5"]}

Result_one_two = {key:list(set(Dict_one[key])-set(Dict_two[key])) for key in Dict_one.keys()}
Result_two_one = {key:list(set(Dict_two[key])-set(Dict_one[key])) for key in Dict_two.keys()}
letmecheck
  • 1,183
  • 8
  • 17
0

You can try a couple of dict comprehensions:

Dict_one = {"A": ["a1", "a2", "a3"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c4"]}

Dict_two = {"A": ["a1"], "B": ["b1", "b2"], "C":["c1", "c2", "c3", "c5"]}

# Remove this line and just loop over DictOne if using Python 3.6+
sort_keys = sorted(Dict_one)

Result_one_two = {k: [x for x in Dict_one[k] if x not in Dict_two[k]] for k in sort_keys}
Result_two_one = {k: [x for x in Dict_two[k] if x not in Dict_one[k]] for k in sort_keys}

print(Result_one_two)
print(Result_two_one)

Which Outputs:

{'A': ['a2', 'a3'], 'B': [], 'C': ['c4']}
{'A': [], 'B': [], 'C': ['c5']}

Note: If you are not using Python 3.6+, iterating over the keys in sorted order or using a collections.OrderedDict()is necessary, since order is not guaranteed. Otherwise, you can just loop over the keys normally and order is retained.

This also assumes Dict_one and Dict_two have the same keys.

RoadRunner
  • 25,803
  • 6
  • 42
  • 75