Python: Comparing value overlap between keys in a dictionary - python

I have a dict like this:
dict = defaultdict(list, {'a': [['1', '2', 'A', 'cat'],
['1', '3', 'A', 'dog']],
'b': [['1', '2', 'A', 'cat'],
['1', '3', 'A', 'dog']],
'c': [['1', '2', 'A', 'cat'],
['2', '2', 'A', 'snake'],
['2', '2', 'A', 'bird']]}
I'd like to get all pairwise comparisons for overlapping values using the full list for each value. (Every position in the value list must match for it to be considered a match between keys)
Since a and b share ['1', '3', 'A', 'dog'] and c doesn't, a/b: ['1', '3', 'A', 'dog'].
a, b, c, all share ['1', '2', 'A', 'cat'], a/b/c: ['1', '2', 'A', 'cat'].
Only c has ['2', '2', 'A', 'snake'], so c: ['2', '2', 'A', 'snake']
Preferred output is a dictionary combining the above, something like
combine_dict = {'a/b': ['1', '3', 'A', 'dog'], 'a/b/c': ['1', '2', 'A', 'cat'], 'c': [['2', '2', 'A', 'snake'], ['2', '2', 'A', 'bird']]}

You can use collections.defaultdict:
import collections
d = {'a': [['1', '2', 'A', 'cat'], ['1', '3', 'A', 'dog']], 'b': [['1', '2', 'A', 'cat'], ['1', '3', 'A', 'dog']], 'c': [['1', '2', 'A', 'cat'], ['2', '2', 'A', 'snake'], ['2', '2', 'A', 'bird']]}
new_d = collections.defaultdict(list)
for a, b in d.items():
for i in b:
new_d[tuple(i)].append(a)
new_r = collections.defaultdict(list)
for a, b in new_d.items():
new_r['/'.join(b)].append(list(a))
new_result = {a:b[0] if len(b) == 1 else b for a, b in new_r.items()}
Output:
{'a/b/c': ['1', '2', 'A', 'cat'], 'a/b': ['1', '3', 'A', 'dog'], 'c': [['2', '2', 'A', 'snake'], ['2', '2', 'A', 'bird']]}

Related

Issue with single line nested for loop in Python

I have data that exports in a string
output = '012345678910abcdefghijkl'
cleaned_output = [output[index:index + 4] for index in range(0, len(output), 4)]
cleaned_output = [cleaned_output[i][item] for i in range(0, len(cleaned_output)) for item in range(0,len(cleaned_output[i]))]
Which returns:
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '1', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']
However, I am looking to return the below, any ideas on where I am going wrong?
[['0', '1', '2', '3'], ['4', '5', '6', '7'], ['8', '9', '1', '0'], ['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j', 'k', 'l']]
You should just split your input into chunks of 4 and then convert them directly to lists:
cleaned_output = [list(output[i:i+4]) for i in range(0, len(output), 4)]
Output:
[['0', '1', '2', '3'], ['4', '5', '6', '7'], ['8', '9', '1', '0'], ['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j', 'k', 'l']]

Array Exchange and Reversing problem on Code Wars

# before
my_list = ['a', 'b', 'c']
other_list = [1, 2, 3]
exchange_with(my_list, other_list)
# after
my_list == [3, 2, 1]
other_list == ['c', 'b', 'a']
So I just finished solving the problem and I thought i had solved it with my solution below which was
def exchange_with(a, b):
a , b = b , a
print(a[::-1])
print("\n")
print(b[::-1])
and the solution comes out right but when I submit it it says
Test Results:
Log (MY RESULTS)
['c', 'b', 'a']
['7', '6', '5', '4', '3', '2', '1']
====================================================
['1', '2', '3', '4', '5', '6', '7'] should equal ['c', 'b', 'a']
['a', 'b', 'c'] should equal ['7', '6', '5', '4', '3', '2', '1']
I am very confused on what I did wrong I swapped each list and reversed it but it won't let me submit my solution
from what I understand here:
# before
my_list = ['a', 'b', 'c']
other_list = [1, 2, 3]
exchange_with(my_list, other_list)
# after
my_list == [3, 2, 1]
other_list == ['c', 'b', 'a']
you have to mutate the lists and the 'Test results' will evaluate your mutation, in which case you can try:
def exchange_with(my_list, other_list):
my_list[:], other_list[:] = other_list[::-1], my_list[::-1]
how it works (should not be used in your solution):
my_list = ['c', 'b', 'a']
other_list = ['7', '6', '5', '4', '3', '2', '1']
exchange_with(my_list, other_list)
print(my_list)
print(other_list)
output:
['1', '2', '3', '4', '5', '6', '7']
['a', 'b', 'c']

Given nested list element, find the one level back list value

Say i have
List=[[[['a','b'],['c','d'],['e','f']],[['1','2'],['3','4'],['5','6']]],[[['a','b'],['c','d'],['e','f']],[['1','2'],['3','4'],['5','6']]]]
i know that if i call List[0][0] i will get [['a', 'b'], ['c', 'd'], ['e', 'f']], and so on.
Is there any built-in or external python function(suppose its func(a)) or way to get the nested list element a one level back?
So if i call func(List[0][1]) those function will return List[0] or when i call func(List[1][0][1]) those function will return List[1][0] but if i call func(List) it will return List since it's already at the root. I've been searching for this kind of problem for hours but still couldn't find the solution.
You can use the following recursive function:
def get_parent_list(the_elem, the_list):
if (the_elem == the_list):
return (True, the_elem)
elif the_elem in the_list:
return (True, the_list)
else:
for e in the_list:
if (type(e) is list):
(is_found, the_parent) = get_parent_list(the_elem, e)
if (is_found):
return (True, the_parent)
return (False, None)
Testing it out:
my_list=[[[['a','b'],['c','d'],['e','f']],[['1','2'],['3','4'],['5','6']]],
[[['a','b'],['c','d'],['e','f']],[['1','2'],['3','4'],['5','6']]]]
Test Case 1:
the_child = my_list[0][1][1]
the_flag, the_parent = get_parent_list(the_child, my_list)
print (the_flag)
print (the_child)
print (the_parent)
Result:
True
['3', '4']
[['1', '2'], ['3', '4'], ['5', '6']]
Test Case 2:
the_child = my_list[0][1]
the_flag, the_parent = get_parent_list(the_child, my_list)
print (the_flag)
print (the_child)
print (the_parent)
Result:
True
[['1', '2'], ['3', '4'], ['5', '6']]
[[['a', 'b'], ['c', 'd'], ['e', 'f']], [['1', '2'], ['3', '4'], ['5', '6']]]
Test Case 3:
the_child = my_list[:]
the_flag, the_parent = get_parent_list(the_child, my_list)
print (the_flag)
print (the_child)
print (the_parent)
Result:
True
[[[['a', 'b'], ['c', 'd'], ['e', 'f']], [['1', '2'], ['3', '4'], ['5', '6']]], [[['a', 'b'], ['c', 'd'], ['e', 'f']], [['1', '2'], ['3', '4'], ['5', '6']]]]
[[[['a', 'b'], ['c', 'd'], ['e', 'f']], [['1', '2'], ['3', '4'], ['5', '6']]], [[['a', 'b'], ['c', 'd'], ['e', 'f']], [['1', '2'], ['3', '4'], ['5', '6']]]]
Test Case 4:
the_child = my_list[0][1] + ['Non-existent value']
the_flag, the_parent = get_parent_list(the_child, my_list)
print (the_flag)
print (the_child)
print (the_parent)
Result:
False
[['1', '2'], ['3', '4'], ['5', '6'], 'Non-existent value']
None

How to flatten a dictionary with nested sequences into a single sequence with all values and keys?

I have a workable solution that returns a set:
>>> a = {'a': {'1', '2', '3'}, 'b': {'4', '5', '6'}, 'c': {'7', '8', '9'}}
>>> def flatten_nested(a):
temp = set(
[value for value_set in a.values() for value in value_set]
)
return temp | a.keys()
>>> flatten_nested(a)
>>> {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c'}
I wondered if there was some itertools.chain-like function already built in to Python to do something similar?
I guess more simple is this:
>>> set.union(set(a), *a.values())
{'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c'}
Or, here's the same thing via the bound method:
>>> set(a).union(*a.values())
{'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c'}
If the values are already sets then wims answer is the simplest, but to work for iterables like a list, tuples etc.. you would have to map to a set i.e set(a).union(map(set, a.values()) or you could union the chain of all the values with the view of the keys:
from itertools import chain
def flatten_nested(a):
return a.keys() | chain(*a.values()) # a.viewkeys() python2

merge complex matrix with python

I have a complex matrix that looks like this:
[[ ['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[ ['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h'] ] ]
I want to turn it into this:
['x', '1a', '2b', '3c', '4d'],
['y', '5e', '6f', '7g', '8h']
I'm busting my head but not managing to achieve the result. Also, even though I only have two groups of nested 5-items long lists, in theory I want to solve this for an infinite number of groups of the same size.
You can use a dict here:
>>> from operator import add
>>> lis = [[ ['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[ ['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h'] ] ]
>>> dic = {}
for item in lis:
for x in item:
k, v = x[0], x[1:]
if k in dic:
dic[k] = map(add, dic[k], v)
else:
dic[k] = v
...
>>> dic
{'y': ['5e', '6f', '7g', '8h'], 'x': ['1a', '2b', '3c', '4d']}
#list of lists
>>> [[k] + v for k, v in dic.iteritems()]
[['y', '5e', '6f', '7g', '8h'], ['x', '1a', '2b', '3c', '4d']]
Another solution using zip, reduce and a list comprehension:
>>> from operator import add
>>> def func(x, y):
... return map(add, x, y[1:])
>>> [[item[0][0]] + reduce(func, item[1:], item[0][1:]) for item in zip(*lis)]
[['x', '1a', '2b', '3c', '4d'], ['y', '5e', '6f', '7g', '8h']]
Here's a "fun" solution. Since you did not provide any information about your array's structure, I assumed the easiest variant:
import numpy
a = numpy.array([[
['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[
['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h']]],
dtype=numpy.object)
res = a[0].copy()
for chunk in a[1:]:
res[:,1:] += chunk[:,1:]
print(res)

Categories

Resources