Split a list into unequal chunks specified by a dictionary - python

So here is my problem I have a list of size eleven along with a dictionary which tells us how the list should be split. So here the first index should contain the sublist [14, 10, 2, 4], the second index [12, 8, 8, 5] and so on.
l = [14, 10, 2, 4, 12, 8, 8, 5, 9, 2, 7]
dico = dict()
dico[0] = 4
dico[1] = 4
dico[2] = 3
dico
>>> {0: 4, 1: 4, 2: 3}
Eventually the expected behavior is the following
{0:[14, 10, 2, 4], 1:[12, 8, 8, 5], 2:[9, 2, 7]}
Note that retaining the order of the initial list is important.

Given your sample data and a reasonably young Python version (that maintains insertion order for iteration of dicts), you can simply do:
i = iter(l)
{k: [next(i) for _ in range(v)] for k, v in dico.items()}
# {0: [14, 10, 2, 4], 1: [12, 8, 8, 5], 2: [9, 2, 7]}

new_d = {}
for key in dico:
new_d[key] = l[:dico[key]]
l[:dico[key]] = []
print(new_d)
{0: [14, 10, 2, 4], 1: [12, 8, 8, 5], 2: [9, 2, 7]}

I will offer this option:
l = [14, 10, 2, 4, 12, 8, 8, 5, 9, 2, 7]
l2 = l.copy()
dico = {0: 4, 1: 4, 2: 3}
for key, val in dico.items():
for j in range(dico[key]):
if j == 0:
dico[key] = []
dico[key].append(l2.pop(0))
print(dico)
print(l)
Output:
{0: [14, 10, 2, 4], 1: [12, 8, 8, 5], 2: [9, 2, 7]}
[14, 10, 2, 4, 12, 8, 8, 5, 9, 2, 7]

Related

Given two lists of lists find specific matches - fastest solution

Given two lists of lists of arbitrary length, let's say list1 and list2 I want to divide the lists in list1 into subsets of lists, if they contain only one of the lists of list2.
I give you a specific example:
list1 = [[1, 2, 3, 4], [1, 2, 3, 5, 6, 8], [1, 2, 3, 6, 7], [1, 2, 3, 6, 8, 9, 10],
[1, 2, 3, 6, 8, 11, 12], [1, 2, 4, 5, 9, 10], [1, 2, 4, 5, 11, 12],
[1, 2, 5, 6, 7, 9, 10], [1, 2, 5, 6, 7, 11, 12], [1, 2, 5, 6, 8, 9, 10],
[1, 2, 5, 6, 8, 11, 12], [3, 4, 5, 6, 8], [3, 5, 9, 10], [3, 5, 11, 12],
[4, 6, 7], [4, 6, 8, 9, 10], [4, 6, 8, 11, 12], [9, 10, 11, 12]]
list2 = [[2], [6, 7], [6, 8], [9,9]]
and then desired outcome of the function would be for "inner" matches:
[[1, 2, 3, 4],
[1, 2, 4, 5, 11, 12],
[4, 6, 7],
[3, 4, 5, 6, 8],
[4, 6, 8, 11, 12],
[3, 5, 9, 10],
[9, 10, 11, 12]]
and for the "outer" matches (that are consequently the remaining items in list_1):
[(1, 2, 5, 6, 8, 11, 12),
(1, 2, 5, 6, 7, 11, 12),
(4, 6, 8, 9, 10),
(1, 2, 5, 6, 7, 9, 10),
(1, 2, 3, 5, 6, 8),
(1, 2, 3, 6, 8, 11, 12),
(1, 2, 3, 6, 7),
(3, 5, 11, 12),
(1, 2, 4, 5, 9, 10),
(1, 2, 5, 6, 8, 9, 10),
(1, 2, 3, 6, 8, 9, 10)]
I coded a quick and dirty solution that produces the desired outcome, but does not scale well for very long lists (for example 100000 & 2500).
My solution:
from itertools import chain
def find_all_sets(list1,list2):
d = {}
d2 = {}
count = 0
for i in list2:
count = count + 1
set2 = set(i)
d['set'+str(count)] = set2
d['lists'+str(count)] = []
first = []
d2['match'+str(count)] = []
for a in list1:
set1 = set(a)
if d['set'+str(count)].issubset(set1) == True:
first.append(a)
d['lists'+str(count)].append(first)
d2['match'+str(count)].append(d['lists'+str(count)])
count = 0
count2 = -1
d3 = {}
all_sub_lists = []
for i in d2.values():
count = count + 1
count2 = count2 + 1
d3['final'+str(count)] = []
real = []
for item in i:
for each_item in item:
for each_each_item in each_item:
seta= set(each_each_item)
save = []
for i in list2:
setb = set(i)
a=setb.issubset(seta)
save.append(a)
index_to_remove = count2
new_save = save[:index_to_remove] + save[index_to_remove + 1:]
if True not in new_save:
real.append(each_each_item)
d3['final'+str(count)].append(real)
all_sub_lists.append(real)
inner_matches = list(chain(*all_sub_lists))
setA = set(map(tuple, inner_matches))
setB = set(map(tuple, list1))
outer_matches = [i for i in setB if i not in setA]
return inner_matches, outer_matches
inner_matches, outer_matches = find_all_sets(list1,list2)
I am looking for a faster way to process large lists. Please excuse if the terminology of "inner" an "outer" matches is unclear. I did not know how else to call them.
Here is my suggestion (let me know if you need it as a function):
inner_matches=[]
outer_matches=[]
for i in list1:
if sum(1 for k in list2 if set(k).intersection(set(i))==set(k))==1:
inner_matches.append(i)
else:
outer_matches.append(i)
print(inner_matches)
#[[1, 2, 3, 4], [1, 2, 4, 5, 11, 12], [3, 4, 5, 6, 8], [3, 5, 9, 10], [4, 6, 7], [4, 6, 8, 11, 12], [9, 10, 11, 12]]
print(outer_matches)
#[[1, 2, 3, 5, 6, 8], [1, 2, 3, 6, 7], [1, 2, 3, 6, 8, 9, 10], [1, 2, 3, 6, 8, 11, 12], [1, 2, 4, 5, 9, 10], [1, 2, 5, 6, 7, 9, 10], [1, 2, 5, 6, 7, 11, 12], [1, 2, 5, 6, 8, 9, 10], [1, 2, 5, 6, 8, 11, 12], [3, 5, 11, 12], [4, 6, 8, 9, 10]]
Here's a solution that uses issubset() to detect the inner lists. Using your sample data it's faster than your algorithm by a factor of nearly 4.
inner = []
outer = []
search_sets = [set(l) for l in list2]
for l in list1:
if sum(s.issubset(l) for s in search_sets) == 1:
inner.append(l)
else:
outer.append(l)
print(f'{inner = }')
print()
print(f'{outer = }')
Output
inner = [[1, 2, 3, 4], [1, 2, 4, 5, 11, 12], [3, 4, 5, 6, 8], [3, 5, 9, 10], [4, 6, 7], [4, 6, 8, 11, 12], [9, 10, 11, 12]]
outer = [[1, 2, 3, 5, 6, 8], [1, 2, 3, 6, 7], [1, 2, 3, 6, 8, 9, 10], [1, 2, 3, 6, 8, 11, 12], [1, 2, 4, 5, 9, 10], [1, 2, 5, 6, 7, 9, 10], [1, 2, 5, 6, 7, 11, 12], [1, 2, 5, 6, 8, 9, 10], [1, 2, 5, 6, 8, 11, 12], [3, 5, 11, 12], [4, 6, 8, 9, 10]]

List comprehension logic not working and I'm not sure why [duplicate]

This question already has answers here:
Common elements between two lists with no duplicates
(7 answers)
Closed 3 years ago.
The exercise I'm doing requires me to create and print out a list containing all of the common elements in the 2 following lists without duplicates:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
I'm trying to create the new list in one line of code and I think my logic is correct but obviously there's an issue with it somewhere.
Here's what is currently not working:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
common_list = []
common_list = [nums for nums in a if (nums in b and nums not in common_list)]
print(common_list)
I expect to get [1, 2, 3, 5, 8, 13] but the 1 is still duplicated even though I have the 'nums not in common_list' condition so I end up getting
[1, 1, 2, 3, 5, 8, 13]
As already mentioned in other answers and comment, your problem is that, during the list comprehension, common_list is empty.
Now for practical solutions: if order is not important, sets are your friends:
common_list = list(set(a) & set(b))
and if order is important, sets are still your friends:
seen = set()
bset = set(b) # makes `in` test much faster
common_list = []
for item in a:
if item in seen:
continue
if item in bset:
common_list.append(item)
seen.add(item)
Instead of using a list I suggest you to use a set to avoid duplicate values.
common_set = set()
You can add items by:
common_set.add(value)
Finally you can print values by:
print(common_set)
you can use enumerate:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
res = [i for n, i in enumerate(a) if i not in a[:n] and i in b]
print (res)
output:
[1, 2, 3, 5, 8, 13]
One way to do this with lists is (assuming that the one of the lists has no duplicates):
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
c = [x for x in a if x in b]
print(c)
# [1, 2, 3, 5, 8, 13]
or, for any list:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
c = []
for x in a + b:
if x in a and x in b and x not in c:
c.append(x)
print(c)
# [1, 2, 3, 5, 8, 13]
But sets are much better suited for this:
a = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89}
b = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
c = a.intersection(b)
print(c)
# {1, 2, 3, 5, 8, 13}
One-liner:
list(set(a).intersection(b))

Use max() function to get keys of dict items with max length

I have two dictionaries like so:
concave relations : {6: [2, 3, 4, 5], 2: [6], 3: [6], 4: [6], 5: [6]}
convex relations : {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]}
Previously I could find the key which corresponds to the item of max length using this code:
bottom_face = max(concave, key=lambda x:len(concave[x]))
Since the concave dict doesn't contain any items of the same length
Since this is not the case in the convex dict, and I want to return all of the keys which have max length items, I tried using the following:
possible_top_faces = [i for i, x in enumerate(convex) if x == max(convex, key=lambda x:len(convex[x]))]
But it is just returning:
[0]
Instead of the keys 1, 6, 7, 8, 9, 10, 11.
Can anyone help me out?
You can get the largest length of any key in convex, and use that as your standard for filtering out other keys in convex:
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]
}
longest_len = max(map(len, convex.values()))
max_lens = [k for k, v in convex.items() if len(v) == longest_len]
print(max_lens) # [1, 6, 7, 8, 9, 10, 11]

Merging the 2 lists into 1 which are values in a Dictionary

Hello all I am very new to the programming.
I have a dictC
dictC = {'a':[1,2,3,4,5],'b':[5,6,7,8,9,10]}
I want my output like
mergedlist = [1,2,3,4,5,6,7,8,9,10]
Could any one help me with the logic to define a function?
I have tried some thing like this
enter code here
dictC = {'a': [1, 2, 3, 4, 5, 6, 7], 'b': [3, 7, 8, 9, 10]}
result = MergeDictValues(dictC)
print result
dictC = {'a': [1, 2, 3, 4, 5, 6, 7], 'b': [3, 7, 8, 9, 10]}
dictc= (dictC.values())
dictc.extend(dictc)
print dictc
def MergeDictValues(inputDict):
resultList = []
mergedList = # I am missing my logic here
mergedList.extend( )
return resultList()
MergeDictValues(dictc)
resultList= MergeDictValues(dictc)
print resultList
mergedlist = dictC['a']+ dictC['b']
edit - wait - do you know there are repeated elements in the list( last element of list 1 is 5, but so is the first element of list 2) - is this an invariant feature of the data. More info required I think..
def MergeDictValues(dictC):
return [x for y in dictC.values() for x in y]
Input :
dictC = {'a':[1,2,3,4,5],'b':[5,6,7,8,9,10]}
MergeDictValues(dictC)
Out put :
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]
Pythons dicts are unordered. If you iterate over the keys, you should sort them first. You might get [5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5] as a result otherwise.
You could use a double list comprehension :
dictC = {'a':[1,2,3,4,5],'b':[5,6,7,8,9,10]}
print([x for key in sorted(dictC) for x in dictC[key]])
# [1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]
or sum to add the lists:
print(sum([dictC[key] for key in sorted(dictC)], []))
# [1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]

How to sort a nested dictionary by the a nested value?

Lets say you have this nested dictionary:
myDict = {
0: { 'bob': [1, 9, 4, 6, 7],
'jack': [2, 6, 9, 8, 5, 0]}
1: { 'dom': [1, 7, 8, 5],
'dean': [1, 9]}
}
How do you sort myDict[0] by the greatest of the last three values, so the output can be something like (with jack ahead of bob):
jack -> 8
bob -> 7
Thank you in advance
one solution is to use an orderd dictionary:
from collections import OrderedDict
def my_ordered_dict(d):
return OrderedDict(sorted(d.items(),
key=lambda t: max(t[1][-3:]),
reverse=True))
myDict = {
0: my_ordered_dict({'bob': [1, 9, 4, 6, 7],
'jack': [2, 6, 9, 8, 5, 0]}),
1: my_ordered_dict({'dom': [1, 7, 8, 5],
'dean': [1, 9]})
}
print myDict[0]
print myDict[1]
ouputs:
OrderedDict([('jack', [2, 6, 9, 8, 5, 0]), ('bob', [1, 9, 4, 6, 7])])
OrderedDict([('dean', [1, 9]), ('dom', [1, 7, 8, 5])])
Please note in the second case dean gets ahead of dom even if its list has two elements only.
Code :
myDict = {
0: { 'bob': [1, 9, 4, 6, 7],
'jack': [2, 6, 9, 8, 5, 0]},
1: { 'dom': [1, 7, 8, 5],
'dean': [1, 9]}
}
myDict[0] = sorted(myDict[0].items(),key=lambda (k,v) : max(v[-3:]),reverse=True)
print(myDict)
Output :
{0: [('jack', [2, 6, 9, 8, 5, 0]), ('bob', [1, 9, 4, 6, 7])], 1: {'dean': [1, 9], 'dom': [1, 7, 8, 5]}}
Explanation :
Convert myDict[0] to (key,value) pairs & then sort it by the max value of the last 3 elements in the value list.
Dictionaries are accessed by key's, you can't sort them in python. You can however, EXTRACT the data and put it into a list - after which, sorting the data is rather easy!
myDict = {
0: { 'bob': [1, 9, 4, 6, 7],
'jack': [2, 6, 9, 8, 5, 0]}
1: { 'dom': [1, 7, 8, 5],
'dean': [1, 9]}
}
For example, you can do:
list_one = (myDict[0]['bob'][-3:])
If you want the greatest of the last three values:
greatest = list.sort(list_one)[-1] #gets the last value

Categories

Resources