Combining Lists Until Desired List Is Made - python

If I have the following Dictionary of Lists:
{1: [2], 2: [1, 3, 5], 3: [2, 4], 4: [3, 7], 5: [2, 6], 6: [5], 7: [8, 4], 8: [7]}
I want to know the keys I'll need a full set of:
[1,2,3,4,5,6,7,8]
Using the smallest number of keys. For this particular problem for example it would be:
keys needed: [2,5,7]
While the order doesn't matter I want to use as few keys as possible. Is there an easy way to do this and to test if my answer is the shortest possible answer?

Here comes the bruteforce solution, using itertools.combinations:
from itertools import combinations
data = {1: [2], 2: [1, 3, 5], 3: [2, 4], 4: [3, 7], 5: [2, 6], 6: [5], 7: [8, 4], 8: [7]}
desired_set = set([1, 2, 3, 4, 5, 6, 7, 8])
n = len(data)
all_values = set(x for values in data.values() for x in values)
if all_values.issuperset(desired_set):
print("There must be a solution...")
n = len(data)
for i in range(0, n + 1):
for combination in combinations(data, i):
values = set(x for key in combination for x in data[key])
if values.issuperset(desired_set):
print("FOUND!")
print("Keys needed : %r" % list(combination))
print("Values : %r" % list(values))
quit()
else:
print "Not possible. Not even trying"
It outputs:
FOUND!
Keys needed : [2, 4, 5, 7]
Values : [1, 2, 3, 4, 5, 6, 7, 8]
Worst case complexity is O(2**n) though, so don't use it on big datasets!
Note that you need 4 as key to get 7 as value.

If you mean values instead of keys, here you go.
d = {1: [2], 2: [1, 3, 5], 3: [2, 4], 4: [3, 7], 5: [2, 6], 6: [5], 7: [8, 4], 8: [7]}
#get the values from all elements and use a set to remove duplicate and then use sum to flatten the list.
list(set(sum(d.values(),[])))
Out[806]: [1, 2, 3, 4, 5, 6, 7, 8]

If you just want the keys in order, you can call sorted() directly on the dictionary.
some_dict = {1: [2], 2: [1, 3, 5], 3: [2, 4], 4: [3, 7], 5: [2, 6], 6: [5], 7: [8, 4], 8: [7]}
keys = sorted(some_dict)
print(keys)
[1, 2, 3, 4, 5, 6, 7, 8]
If, on the other hand, you want all the unique VALUES in the dictionary in sorted order, you should sort a set.
values = sorted({x for key in some_dict for x in some_dict[key]})
print(values)
[1, 2, 3, 4, 5, 6, 7, 8]
I don't know why you would want to use the shortest possible number of keys, but you can do so as follows.
wanted = set(range(1, 9))
seen = set()
for key in some_dict:
seen |= set(some_dict[key])
if seen == wanted:
break

Related

Find intersection of dictionary values list

I have two dictionaries with the same keys, while the values are variant:
a = {1: [1, 2, 3, 4, 5], 2: [6, 7, 8], 3: [1, 3, 5, 7, 9]}
b = {1: [2, 3, 4, 7], 2: [6, 7], 3: [1, 3, 15, 10]}
I'm trying to get the intersection under the same keys. I want this output:
{1: [2, 3, 4], 2: [6, 7], 3: [1, 3]}
I tried with this command:
dict(zip(a.keys() and b.keys(), a.values() and b.values()))
output: {1: [2, 3, 4, 7], 2: [6, 7], 3: [1, 3, 15, 10]}
However, the output is the following, which is wrong:
{1: [2, 3, 4, 7], 2: [6, 7], 3: [1, 3, 15, 10]}
I think it is pretty clear. If not, please ask for clarification.
Assuming,
I have two dictionaries with the same keys
a = {1: [1, 2, 3, 4, 5], 2: [6, 7, 8], 3: [1, 3, 5, 7, 9]}
b = {1: [2, 3, 4, 7], 2: [6, 7], 3: [1, 3, 15, 10]}
c = {}
for key, val in a.items():
c[key] = []
for i in val:
if i in b[key]:
c[key].append(i)
print(c)
The output is:
{1: [2, 3, 4], 2: [6, 7], 3: [1, 3]}
If you know the dictionaries have the same keys, you could do
c = {}
for key, list_a, list_b in zip(a.keys(), a.values(), b.values()):
c[key] = [value for value in list_a if value in list_b]
Or:
c = {}
for key, list_a, list_b in zip(a.keys(), a.values(), b.values()):
c[key] = list(set(list_a).intersection(list_b))
If you're not sure they have the same keys, just add a condition, like
c = {}
for key_a, list_a, key_b, list_b in zip(a.keys(), a.values(), b.keys(), b.values()):
if key_a == key_b:
c[key_a] = [value for value in list_a if value in list_b]
c= {key:list(set(a[key]) & set(b[key])) for key in a}
Explanation: using dictionary comprehension, I went through each key of 'a', & create an intersection of list of values corresponding to that key in both the dictionaries 'a' & 'b'

how to classify a list of lists by elements length?

I have a list of lists, looks like this :
List=[[1,3],[3,4,7,9],[4,7],[2,4,5,3],[5,7,4]]
I want to classify the list elements according to their length, so the result looks like this:
2ElelmentSublist=[[1,3],[4,7]]
4ElementSublist=[[3,4,7,9],[2,4,5,3]]
....
And so on.
I read a post about itertools.groupby(),
But I couldn’t figure out how to apply it in my case.
Any pythonic way to do so?
Note: no need to have the result in separate variables,I need a way to know how many types of lengths I have, and a way to reach every group separately.
Thank you in advance.
You can't make lists with dynamic names to be decided at run-time (like your 2ElementSublist or so.)
But you can design a dictionary with keys as length, and values as lists of lists.
Try this:
result = {}
for L in List:
result.setdefault(len(L), list()).append(L)
print(result)
and you will see
{2: [[1, 3], [4, 7]], 4: [[3, 4, 7, 9], [2, 4, 5, 3]], 3: [[5, 7, 4]]}
.setdefault(k, d) either gives you access to the dictionary value of key k, or initialize with a default value d. And you append each list.
Might not be the most pythonic, but you can call values similar to how you wanted.
x = [[1,3],[3,4,7,9],[4,7],[2,4,5,3],[5,7,4]]
dic = {f"{len(i)}_elelment": [] for i in x}
for i in x:
dic[f"{len(i)}_elelment"].append(i)
# {'2_elelment': [[1, 3], [4, 7]],
# '4_elelment': [[3, 4, 7, 9], [2, 4, 5, 3]],
# '3_elelment': [[5, 7, 4]]}
Since you have mentioned you need the list grouped by len and need them in seperate variable I think you will be needing a dict as your final output.
from itertools import groupby, chain
from collections import defaultdict
List=[[1,3],[3,4,7,9],[4,7],[2,4,5,3],[5,7,4]]
res = defaultdict(list)
for _, v in groupby(sorted(List, key=len)):
l = list(chain(*v))
res[len(l)].append(l)
# Output : defaultdict(list,
{2: [[1, 3], [4, 7]],
3: [[5, 7, 4]],
4: [[3, 4, 7, 9], [2, 4, 5, 3]]})
You can try this:
List = [[1,3],[3,4,7,9],[4,7],[2,4,5,3],[5,7,4]]
sizes = set([(len(element)) for element in List])
result = {}
for element in List:
if len(element) not in result.keys():
result[len(element)] = []
result[len(element)].append(element)
print(result)
And result is:
{2: [[1, 3], [4, 7]], 4: [[3, 4, 7, 9], [2, 4, 5, 3]], 3: [[5, 7, 4]]}
Use groupby by len:
Ex:
from itertools import groupby
lst = [[1,3],[3,4,7,9],[4,7],[2,4,5,3],[5,7,4]]
print( [list(v) for k, v in groupby(sorted(lst, key=len), key=len)] )
#or
print( {k: list(v) for k, v in groupby(sorted(lst, key=len), key=len)} )
Output:
[[[1, 3], [4, 7]], [[5, 7, 4]], [[3, 4, 7, 9], [2, 4, 5, 3]]]
{2: [[1, 3], [4, 7]], 3: [[5, 7, 4]], 4: [[3, 4, 7, 9], [2, 4, 5, 3]]}

python updating global dict inside recursive function

I am trying to find all permutations of elements in a list and add it to a global dictionary
Code:
outp={}
k=0
def func(i,arr):
global outp
global k
arr=arr.copy()
for j in range(i,len(list)):
arr[i],arr[j] = arr[j],arr[i]
if i!=j or i==0:
k=k+1
print("\n\n",arr,k)
outp[k]=arr
print("\n",outp)
func(i+1,arr)
list = [1,2,3,8]
func(0,list)
Output below:
Till 4th element it updated correctly. During 5th element, it updated both 5th and 3rd element in the dictionary. I don't know why it is happening. Kindly help
[1, 2, 3, 8] 1
{1: [1, 2, 3, 8]}
[1, 2, 8, 3] 2
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3]}
[1, 3, 2, 8] 3
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3], 3: [1, 3, 2, 8]}
[1, 3, 8, 2] 4
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3], 3: [1, 3, 2, 8], 4: [1, 3, 8, 2]}
[1, 8, 2, 3] 5
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3], 3: [1, 8, 2, 3], 4: [1, 3, 8, 2], 5: [1, 8, 2, 3]}
You need to place a copy of the array in the dictionary:
outp[k] = arr.copy()
This would be a better way to copy list to a new list.
arr=arr[:] .
https://repl.it/repls/BronzeYellowConversion

Check if dict values exist as keys in another dict

I have two dictionaries:
concave = {6: [2, 3, 4, 5], 2: [6], 3: [6], 4: [6], 5: [6]}
convex = {1: [2, 3, 4, 5], 2: [1, 3, 5], 3: [1, 2, 4], 4: [1, 3, 5], 5: [1, 2, 4], 6: [7, 8, 9, 10], 7: [6, 8, 10, 11], 8: [6, 7, 9, 11], 9: [6, 8, 10, 11], 10: [6, 7, 9, 11], 11: [7, 8, 9, 10]}
And I have returned the keys which have max length values in the convex dict:
max_lens = [1, 6, 7, 8, 9, 10, 11]
For each number in max_lens, I want to check that it does not exist as a key in concave and its values in convex exist as keys in concave.
So in this example, '1' would satisfy this condition as it is not included in concave as a key, but its values in convex are (i.e. 2, 3 4 and 5).
I have tried to figure out how to go about this using for loops/if statements:
for i in enumerate(max_lens):
if i not in concave:
for k,v in convex.items():
for j in v:
That is about as far as I got before getting totally confused. There must be an easier way to do this other than using multiple for loops and if statements?
I'm a bit of a python noob so sorry if this comes across as confusing!
I think I understood (for the record I prefer the explicit concave.keys())
result_dict = {}
for convex_key in max_lens:
result_dict[convex_key] = convex_key not in concave.keys() \
and all(convex_val in concave.keys()
for convex_val in convex[convex_key])
Edit (see comments)
for convex_key in max_lens:
if convex_key not in concave.keys() and \
all(convex_val in concave.keys() for convex_val in convex[convex_key]):
top_face = convex_key
break
Spelling this problem out into steps always helps:
Loop over each of the lengths l in max_lens
Check if l doesn't exist in concave but exists in convex. A conjunction of these two conditions is needed here. If either fails, don't continue.
If the above two conditions are accepted, check if all the values from convex[l] exist in concave.
If the code reaches here with no issues, all the conditions are met.
Demo:
concave = {6: [2, 3, 4, 5], 2: [6], 3: [6], 4: [6], 5: [6]}
convex = {1: [2, 3, 4, 5], 2: [1, 3, 5], 3: [1, 2, 4], 4: [1, 3, 5], 5: [1, 2, 4], 6: [7, 8, 9, 10], 7: [6, 8, 10, 11], 8: [6, 7, 9, 11], 9: [6, 8, 10, 11], 10: [6, 7, 9, 11], 11: [7, 8, 9, 10]}
max_lens = [1, 6, 7, 8, 9, 10, 11]
for l in max_lens:
if l not in concave and l in convex and all(v in concave for v in convex[l]):
print(l)
Output:
1
You can do it with comprehension:
[i for i in max_lens if i not in concave and convex[i] in concave.values()]
Using a simple forloop.
concave = {6: [2, 3, 4, 5], 2: [6], 3: [6], 4: [6], 5: [6]}
convex = {1: [2, 3, 4, 5], 2: [1, 3, 5], 3: [1, 2, 4], 4: [1, 3, 5], 5: [1, 2, 4], 6: [7, 8, 9, 10], 7: [6, 8, 10, 11], 8: [6, 7, 9, 11], 9: [6, 8, 10, 11], 10: [6, 7, 9, 11], 11: [7, 8, 9, 10]}
max_lens = [1, 6, 7, 8, 9, 10, 11]
for i in max_lens:
if (i not in concave): #Check if not in key.
if convex[i] in concave.values(): #Check Value.
print i
Output:
1
If you don't understand a problem easily, it's often a good way, to divide it into several smaller problems:
write a function that checks if a value is not key of a dict:
def is_no_key_in(v, _dict):
return key not in _dict
Since that is too simple return a list of keys that are not in dict:
def no_key_values(_list, _dict):
return [ v for v in _list if is_no_key_in(v, _dict) ]
Now that you only have values that fit your first condition, you can concentrate on your second condition. Since you want that every value of a list is in a list of keys, you can start making a union-like function:
def union(a_lst, b_lst):
return [ a for a in a_lst if a in b_lst]
To make it more into something serving your needs, you could change it to a function that checks for any diffs:
def is_subset(a_lst, b_lst):
return len([a for a in a_lst if a not in b_lst]) == 0
Now you piece the functions together:
def satisfies_conditions(max_lens):
for lens in no_key_values(max_lens, concave):
if is_subset(convex[lens], concave.keys())
yield lens
result = [ lens for lens in satisfies_conditions(max_lens) ]
result now contains all lenses that satisfy your conditions and if you want to change your conditions, you can easily do so. If your code works, you can go on and refactor it. For example you might not need is_no_key_in as it is a very simple function. Then go on and inline it into no_key_values:
def no_key_values(_list, _dict):
return [ v for v in _list if v not in _dict ]
If you write some tests before refactoring (or even writing the code) you can ensure, that your refactoring won't introduce bugs. Then simplify the code step by step. Maybe you will end up with a solution as simple as proposed in other answers here.
(I hope this will also help you with future problems like that :-))

Can I remove a single value from a dictionary?

I have a dictionary and I want to remove a single value from a key:values combination.
For example, when having the following dictionary:
d = {1: [2, 3, 4, 7], 2: [1, 3, 4]}
I'd like to remove the key:value 1:2, so that the dictionary becomes:
{1: [3, 4, 7], 2: [1, 3, 4]}
Is this doable?
You have a dict that holds lists.
The lists can be manipulated in the usual manner
d = {1: [2, 3, 4, 7], 2: [1, 3, 4]}
d[1].remove(2)
print(d)
# {1: [3, 4, 7], 2: [1, 3, 4]}
Well, first find a reference to list, then remove an item with value 2 from list, so:
d[1].remove(2)
d = {1: [2, 3, 4, 7], 2: [1, 3, 4]}
d[1].remove(2)
print d

Categories

Resources