Finding set difference between two complex dictionaries - python-3.x

I have two dictionaries of the following structure:
a) dict1 = {'a':[ [1,2], [3,4] ], 'b':[ [1,2],[5,6] ]}
b) dict2 = {'a':[ [1,2], [5,6] ], 'b':[ [1,2],[7,8] ]}
I need to find the set difference between each key in the dictionary i.e., dict1['a'] - dict2['a'] should return [3,4]. Any thought is appreciated.

The use of mutable items (such as lists) makes the problem MUCH harder, as it precludes the simple use of Python's set data structure. It may be worth making temporary copies/versions which actually use tuples in lieu of those pesky lists:
def tempaux(d):
return dict((k, set(tuple(x) for x in v))
for k, v in d.iteritems())
Now:
def thedifs(dd1, dd2)
d1 = tempaux(dd1)
d2 = tempaux(dd2)
allkeys = set(d1).update(d2)
empty = set()
difs = []
for k in allkeys:
s1 = d1.get(k, empty)
s2 = d2.get(k, empty)
adif = s1 - s2
if adif: difs.append(adif)
return difs
This assumes actual set difference rather than symmetric difference etc. You can of course turn back the tuples into lists before returns, &c, depending on your exact requirements.

>>> s1 = set([(1,2), (3,4)])
>>> s2 = set([(1,2), (5,6)])
>>> s1 - s2
{(3, 4)}

You've got the wrong data structure for what you're trying to do.
Use this instead.
dict1 = {'a': [(1, 2), (3, 4)], 'b': [(1, 2), (5, 6)]}
dict2 = {'a': [(1, 2), (5, 6)], 'b': [(1, 2), (7, 8)]}
Life is simpler when you try to do set operations on immutable objects like tuples.
This will transform your list-of-lists into a list-of-tuples.
>>> dict( (key,[tuple(v) for v in dict1[key]]) for key in dict1 )
{'a': [(1, 2), (3, 4)], 'b': [(1, 2), (5, 6)]}
Here's the complete solution.
>>> dict1t= dict( (key,[tuple(v) for v in dict1[key]]) for key in dict1 )
>>> dict2t= dict( (key,[tuple(v) for v in dict2[key]]) for key in dict2 )
>>> set(dict1t['a'])-set(dict2t['a'])
set([(3, 4)])

applicable to list or dict or number when a and b share the same structure
c={'a':'1','b':'2'}
d={'a':'10','b':'20'}
e={'x':c,'t':15}
f={'x':d,'t':19}
def diff(a,b):
if isinstance(a, int) and isinstance(b, int):
b = b - a
return b
if isinstance(a, str) and isinstance(b, str):
if a.isdigit() and b.isdigit():
b = str(int(b) - int(a))
return b
else:
b = a
return b
if type(a) is list and type(b) is list:
for i in range(len(a)):
b[i] = diff(a[i],b[i])
return b
if type(a) is dict and type(b) is dict:
for k,v in b.iteritems():
b[k] = diff(a[k],b[k])
return b
print diff(e,f)

Related

Finding unique combinations of tuples

Input: 1 2 3 4
Output: (1,2)(3,4)
(1,3)(2,4)
(1,4)(2,3)
I have been able to come up with a solution for the problem but it is efficient. It needs to be optimized.
comb = combinations(Arr,int(n/2))
l = []
for i in comb:
l.append(i)
final_comb = combinations(l,int(n/2))
for i in final_comb:
if is_unique(n,i):
print(i)
def is_unique(n,tup):
k = []
for i in tup:
for j in i:
k.append(j)
if len(set(k)) == n:
return True
return False
The output must be combinations of tuples such that they all have the numbers given as input
Use itertools
from itertools import combinations
list(combinations([1, 2, 3, 4], 2))
>>> [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

How to do Groupby and map in one go in python just like we do in scala

we have a list in Scala :
val testList = List("Sita" -> 1, "Sita" -> 2, "Ram" -> 3, "Ram" -> 4, "Shyam" -> 5)
I applied this on list to group the values by key in Scala:
val res = testList.groupBy(_._1).map { case (k, v) => k -> v.map(_._2).sum }
and i got this as a result:
Map(Shyam -> 5, Ram -> 7, Sita -> 3)
I want to do the same in python Please help me out:
testList = [("Sita", 1), ("Sita", 2), ("Ram", 3), ("Ram", 4), ("Shyam", 5)]
Edit: And what if i have a list like this:
testList = [("Sita_English", 1), ("Sita_Maths", 2), ("Ram_English", 3), ("Ram_Maths", 4), ("Shyam_English", 5)]
testList = [("Sita", 1), ("Sita", 2), ("Ram", 3), ("Ram", 4), ("Shyam", 5)]
from itertools import groupby
out = {v: sum(i[1] for i in g) for v, g in groupby(testList, lambda k: k[0])}
print(out)
Prints:
{'Sita': 3, 'Ram': 7, 'Shyam': 5}
A little explanation:
itertools.groupby() (doc) returns consecutive keys and groups from the iterable. In this case the iterable is tesList. The key function lambda k: k[0] returns first element of the tuple -> so we are grouping along the first element.
The dict comprehension is using this first element as a key and second elements from the group as parameter to the sum() function.
EDIT: Using only map():
testList = [("Sita", 1), ("Sita", 2), ("Ram", 3), ("Ram", 4), ("Shyam", 5)]
from itertools import groupby
from operator import itemgetter
out = dict(map(lambda v:(v[0], sum(map(itemgetter(1), v[1]))), groupby(testList, itemgetter(0))))
print(out)
I think you want to have a solution in functional way:
out = list(map(lambda v:(v[0], sum(map(lambda s: s[1], v[1]))), groupby(testList, key=lambda x: x[0])))

Appending dictionary into a list of tuples

Say I got the following dict :
d = {'x': 1, 'y': 2, 'z': 3}
I want to create a function that appends each key and it's value into a list of tuples, so I coded:
def dict_to_list_of_tuples(dic):
list_of_tuples = []
for key in dic:
list_of_tuples.append((key, dic[key]))
return list_of_tuples
but I get the following output:
[('x', 1), ('y', 2), ('z', 3)]
while I want to get:
[(x, 1), (y, 2), (z, 3)]
Your function is simply list(d.items()):
>>> list(d.items())
[('x', 1), ('y', 2), ('z', 3)]
For printing in the format that you want just make the representation you want with str.format:
>>> "[{}]".format(f", ".join(f"({k}, {v})" for k,v in d.items()) )
'[(x, 1), (y, 2), (z, 3)]'
d = {'x': 1, 'y': 2, 'z': 3}
def dict_to_list_of_tuples(dic):
list_of_tuples = []
for key in dic:
list_of_tuples.append((key, dic[key]))
return list_of_tuples
print(dict_to_list_of_tuples(d))
print("[{}]".format(f", ".join(f"({k}, {v})" for k,v in dict_to_list_of_tuples(d)) ))

Python - eliminating common elements from two lists

If i have two lists:
a = [1,2,1,2,4] and b = [1,2,4]
how do i get
a - b = [1,2,4]
such that one element from b removes only one element from a if that element is present in a.
You can use itertools.zip_longest to zip the lists with different length then use a list comprehension :
>>> from itertools import zip_longest
>>> [i for i,j in izip_longest(a,b) if i!=j]
[1, 2, 4]
Demo:
>>> list(izip_longest(a,b))
[(1, 1), (2, 2), (1, 4), (2, None), (4, None)]
a = [1,2,1,2,4]
b = [1,2,4]
c= set(a) & set(b)
d=list(c)
The answer is just a little modification to this topic's answer:
Find non-common elements in lists
and since you cannot iterate a set object:
https://www.daniweb.com/software-development/python/threads/462906/typeerror-set-object-does-not-support-indexing

Concatenate two values in a pair of 2 tuples

So I'm trying to create a function where it combines the elements of a tuple.
So for example:
[(1,2),("Hi","Bye")] will become ['12', 'HiBye'] after the function is implemented.
How can I achieve this in Python?
For pairs, you can do:
>>> list(map(lambda pair:"%s%s"%pair, [(1,2),("Hi","Bye")]))
['12', 'HiBye']
or if you want to handle arbitrary tuples, not just pairs:
>>> list(map(lambda l:''.join(map(str, l)), [(1,2),("Hi","Bye")]))
['12', 'HiBye']
>>> list(map(lambda l:''.join(map(str, l)), [(1,2,3),("Hi","Bye","Ciao")]))
['123', 'HiByeCiao']
Try this:
L = [(1, 2), ('Hi', 'Bye')]
L = list(map(lambda t : str(t[0]) + str(t[1]), L))
Using list comprehension:
myList = [(1,2),("Hi","Bye")]
answer = [str(t[0]) + str(t[1]) for t in myList]
Try combining map() and reduce() :
import operator
lst = [("1", "2"), ("c", "d")]
map(lambda x: reduce(operator.concat, x, ""), lst)
The matching items must be concatenatable, i.e. you need to convert them to e.g. strings first. Or include it in the code :
import operator
lst = [(1, 2, 3, 52), ("c", "d")]
map(lambda x: reduce(operator.concat, map(str, x), ""), lst)
Using string.join() is also possible (and probably more pythonic):
lst = [(1, 2, 3, 52), ("c", "d")]
map(lambda x: ''.join(map(str, x)), lst)

Resources