I have a python program in which I have a list which resembles the list below:
a = [[1,2,3], [4,2,7], [5,2,3], [7,8,5]]
Here I want to create a dictionary using the middle value of each sublist as keys which should look something like this:
b = {2:[[1,2,3], [4,2,7], [5,2,3]], 8: [[7,8,5]]}
How can I achieve this?
You can do it simply like this:
a = [[1,2,3], [4,2,7], [5,2,3], [7,8,5]]
b = {}
for l in a:
m = l[len(l) // 2] # : get the middle element
if m in b:
b[m].append(l)
else:
b[m] = [l]
print(b)
Output:
{2: [[1, 2, 3], [4, 2, 7], [5, 2, 3]], 8: [[7, 8, 5]]}
You could also use a defaultdict to avoid the if in the loop:
from collections import defaultdict
b = defaultdict(list)
for l in a:
m = l[len(l) // 2]
b[m].append(l)
print(b)
Output:
defaultdict(<class 'list'>, {2: [[1, 2, 3], [4, 2, 7], [5, 2, 3]], 8: [[7, 8, 5]]})
Here is a solution that uses dictionary comprehension:
from itertools import groupby
a = [[1,2,3], [4,2,7], [5,2,3], [7,8,5]]
def get_mid(x):
return x[len(x) // 2]
b = {key: list(val) for key, val in groupby(sorted(a, key=get_mid), get_mid)}
print(b)
Related
I searched the net but couldn't find anything. I am trying to get all possible combinations including all subsets combinations of two lists (ideally n lists). All combinations should include at least one item from each list.
list_1 = [1,2,3]
list_2 = [5,6]
output = [
[1,5], [1,6], [2,5], [2,6], [3,5], [3,6],
[1,2,5], [1,2,6], [1,3,5], [1,3,6], [2,3,5], [2,3,6], [1,5,6], [2,5,6], [3,5,6],
[1,2,3,5], [1,2,3,6],
[1,2,3,5,6]
]
All I can get is pair combinations like [1,5], [1,6], .. by using
combs = list(itertools.combinations(itertools.chain(*ls_filter_columns), cnt))
What is the pythonic way of achieving this?
Here is one way:
from itertools import combinations, product
def non_empties(items):
"""returns nonempty subsets of list items"""
subsets = []
n = len(items)
for i in range(1,n+1):
subsets.extend(combinations(items,i))
return subsets
list_1 = [1,2,3]
list_2 = [5,6]
combs = [list(p) + list(q) for p,q in product(non_empties(list_1),non_empties(list_2))]
print(combs)
Output:
[[1, 5], [1, 6], [1, 5, 6], [2, 5], [2, 6], [2, 5, 6], [3, 5], [3, 6], [3, 5, 6], [1, 2, 5], [1, 2, 6], [1, 2, 5, 6], [1, 3, 5], [1, 3, 6], [1, 3, 5, 6], [2, 3, 5], [2, 3, 6], [2, 3, 5, 6], [1, 2, 3, 5], [1, 2, 3, 6], [1, 2, 3, 5, 6]]
Which has more elements then the output you gave, though I suspect that your intended output is in error. Note that my code might not correctly handle the case in which there is a non-empty intersection of the two lists. Then again, it might -- you didn't specify what the intended output should be in such a case.
Here is another way.
Even though it is not fancy, it cares n_lists easily.
def change_format(X):
output = []
for x in X:
output += list(x)
return output
import itertools
list_1 = [1,2,3]
list_2 = [5,6]
list_3 = [7,8]
lists = [list_1, list_2, list_3]
lengths = list(map(len, lists))
rs_list = itertools.product(*[list(range(1, l+1)) for l in lengths])
output = []
for rs in rs_list:
temp = []
for L, r in zip(lists, rs):
temp.append(list(itertools.combinations(L, r)))
output += list(itertools.product(*temp))
output = list(map(change_format, output))
I have managed to make it work for n-lists with less code, which was a challenge for me.
from itertools import chain, combinations, product
def get_subsets(list_of_lists):
"""
Get all possible combinations of subsets of given lists
:param list_of_lists: consists of any number of lists with any number of elements
:return: list
"""
ls = [chain(*map(lambda x: combinations(e, x), range(1, len(e)+1))) for e in list_of_lists if e]
ls_output = [[i for tpl in ele for i in tpl] for ele in product(*ls)]
return ls_output
list_1 = [1, 2, 3]
list_2 = [5, 6]
list_3 = [7, 8]
ls_filter_columns = [list_1, list_2, list_3]
print(get_subsets(ls_filter_columns))
I have two lists:
a = ["A", "B", "B", "C", "D", "A"]
b = [1, 2, 3, 4, 5, 6]
I want to have a dictionary like the one below:
d = {"A":[1, 6], "B":[2, 3], "C":[4], "D":[5]}
Right now I am doing something like this:
d = {i:[] for i in set(a)}
for c in zip(a, b):
d[c[0]].append(c[1])
Is there a better way to do this?
You can use the dict.setdefault method to initialize each key as a list and then append the current value to it while you iterate:
d = {}
for k, v in zip(a, b):
d.setdefault(k, []).append(v)
With the sample input, d would become:
{'A': [1, 6], 'B': [2, 3], 'C': [4], 'D': [5]}
Running your code, didnt produce the output what you wanted. The below is a bit more verbose but makes it easy to see what the code is doing.
a = ["A", "B", "B", "C", "D", "A"]
b = [1, 2, 3, 4, 5, 6]
c = {}
for a, b in zip(a, b):
if a in c:
if isinstance(a, list):
c[a].append(b)
else:
c[a] = [c[a], b]
else:
c[a] = b
print(c)
OUTPUT
{'A': [1, 6], 'B': [2, 3], 'C': 4, 'D': 5}
An alternative less verbose mode would be to use a default dict with list as the type, you can then append all the items to it. this will mean even single items will be in a list. to me its much cleaner as you will know the data type of each item in the list. However if you really do want to have single items not in a list you can clean it up with a dict comprehension
from collections import defaultdict
a = ["A", "B", "B", "C", "D", "A"]
b = [1, 2, 3, 4, 5, 6]
c = defaultdict(list)
for a, b in zip(a, b):
c[a].append(b)
d = {k: v if len(v) > 1 else v[0] for k, v in c.items()}
print(c)
print(d)
OUTPUT
defaultdict(<class 'list'>, {'A': [1, 6], 'B': [2, 3], 'C': [4], 'D': [5]})
{'A': [1, 6], 'B': [2, 3], 'C': 4, 'D': 5}
How to merge two array and group by key?
Example:
my_list = [3, 4, 5, 6, 4, 6, 8]
keys = [1, 1, 2, 2, 3, 5, 7]
Expected outcome:
[[1, 3, 4], [2, 5, 6], [3, 4], [5, 6], [7, 8]]
If I understand it right, the list of keys map to the list of values. You can use the zip function to iterate through two lists at the same time. Its convenient in this case. Also check up on the beautiful defaultdict functionality - we can use it to fill a list without initialising it explicitely.
from collections import defaultdict
result = defaultdict(list) # a dictionary which by default returns a list
for key, val in zip(keys, my_list):
result[key].append(val)
result
# {1: [3, 4], 2: [5, 6], 3: [4], 5: [6], 7: [8]}
You can then go to a list (but not sure why you would want to) with:
final = []
for key, val in result.items():
final.append([key] + val) # add key back to the list of values
final
# [[1, 3, 4], [2, 5, 6], [3, 4], [5, 6], [7, 8]]
I think you have to write it by your own using set() to remove duplicates, so I have made a function called merge_group
my_list = [3, 4, 5, 6, 4, 6, 8]
keys = [1, 1, 2, 2, 3, 5, 7]
def merge_group(input_list : list, input_key : list):
result = []
i = 0
while i < len(my_list):
result.append([my_list[i], keys[i]])
i += 1
j = 0
while j < len(result):
if j+1 < len(result):
check_sum = result[j] + result[j+1]
check_sum_set = list(set(check_sum))
if len(check_sum) != len(check_sum_set):
result[j] = check_sum_set
j += 1
return result
print(merge_group(my_list, keys))
I have a nested list:
x = [[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]]
I want to iterate over the list and return a new nested list with each list returned with one value missing. So:
new_x = [[2,3,4],[1,3,4],[1,2,4],[1,2,3]]
I have this:
temp_list = []
y = 0
for i in x:
temp_list += i.remove(y)
y+=1
print(x)
But what's happening is each iteration is removing the indexed item so the list goes out of range.
list = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
for count, i in enumerate(list):
if len(i) > 0:
del i[count]
print(list)
For each sublist it deletes the element with an index equal to the index of the sublist
>>>[[2, 3, 4], [1, 3, 4], [1, 2, 4], [1, 2, 3]]
Hope this helps!
You have to use pop instead for remove. See this one:
In [46]: x = [[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]]
In [47]: new_list = [lst for ind, lst in enumerate(x) if lst.pop(ind)]
In [48]: new_list
Out[48]: [[2, 3, 4], [1, 3, 4], [1, 2, 4], [1, 2, 3]]
x = [[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]]
for i in range(0,len(x)):
for j in range (0,len(x)):
if(i==j):
del(x[i][j])
print(x)
new_x = [[2,3,4],[1,3,4],[1,2,4],[1,2,3]]
del(x[i][j]) is used to delete by index from list
i want to turn 'a' to a nested list:
so i design a while loop:
a = [1,2,3,4,5,6,7,8,9,10,11,12]
ll = l = []
m,f,k = 1,0,4
while m <= 3:
l.append(a[int(f):int(k)])
f = f + 4
k = k + 4
ll.append(l)
m = m+1
print(ll)
i want [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]] rather than[[1, 2, 3, 4], [...], [5, 6, 7, 8], [...], [9, 10, 11, 12], [...]]
why the result contains [...]
where is the problem in while loop
Lists are mutable objects, so ll=l=[] means that ll is the
exact same object as l. This can be verified using the is operator:
>>> ll is l
True
This can be demonstrated as follows:
>>> a=b=[]
>>> a
[]
>>> b
[]
>>> a.append(1)
>>> a
[1]
>>> b # For all practical purposes, a is identical to b
[1]
>>> a is b
True
Therefore, the line ll.append(l) creates a recursive object!
Using the pprint module after running the above code states this clearly:
>>> # Run the posted code
>>> import pprint
>>> pprint.pprint(ll)
[[1, 2, 3, 4],
<Recursion on list with id=2032187430600>,
[5, 6, 7, 8],
<Recursion on list with id=2032187430600>,
[9, 10, 11, 12],
<Recursion on list with id=2032187430600>]
The ll list isn't actually necessary, since the l.append method already
appends the newly generated list to the l object and creates a 2D list:
>>> q=[[1,2,3,4]]
>>> q.append([5,6,7,8])
>>> q
[[1, 2, 3, 4], [5, 6, 7, 8]]
The code can be rewritten as follows:
a = [1,2,3,4,5,6,7,8,9,10,11,12]
l = list()
f,k = 0,4
# range(1,4) iterates m through the values [1, 2, 3]
# This includes the first but excludes the last
for m in range(1,4):
# f and k are already integers, so no need for typecasting
# This append statement will append the 1D slice as a single unit
l.append(a[f:k])
# a += 1 is the same as a = a + 1 but is more compact
f += 4
k += 4
print(l)
# Will be [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
If you really need to create two separate empty lists, it is better to do it this way:
>>> q=list()
>>> w=list()
>>> q is w
False