Extending a list - python-3.x

Currently I am tidying up one of my projects by using the more pythonic way of dong things. Now I struggle extending a list by values from a dictionary that are lists.
my_dict = {'a': [1, 2, 3], 'b': [2, 3, 4], 'c': [4, 5, 6]}
criteria = ['a', 'c']
my_list = []
for c in criteria:
my_list.extend(my_dict[c])
Results in [1, 2, 3, 4, 5, 6] which is the sought for result, where as
my_list = []
my_list.extend(my_dict[c] for c in criteria)
Results in a nested list [[1, 2, 3], [4, 5, 6]]. I can't quite find a reason why this is happening

Your code does not work because it attempts to extend the list with the result of the generator comprehension, which is a list of lists:
>>> list(my_dict[c] for c in criteria)
[[1, 2, 3], [4, 5, 6]]
This is because my_dict[c] is itself a list.
A more Pythonic way is to use a list comprehension:
my_dict = {'a': [1, 2, 3], 'b': [2, 3, 4], 'c': [4, 5, 6]}
criteria = ['a', 'c']
my_list = [item for k in criteria for item in my_dict[k]]
>>> my_list
[1, 2, 3, 4, 5, 6]
This uses a nested loop to select the values from the dict by criteria and to flatten the lists that are those values.

Related

How to merge lists value with shared key of two dictionaries?

e.g.
d1 = {'a':[1, 2, 3], 'b': [1, 2, 3]}
d2 = {'a':[4, 5, 6], 'b': [3, 4, 5]}
The output should be like this:
{'a':[1, 2, 3, 4, 5, 6], 'b': [1, 2, 3, 4, 5]}
If the value repeats itself, it should be recorded only once.
Assuming both dictionaries have the same keys and all keys are present in both dictionaries.
One way to achieve could be:
d1 = {'a':[1, 2, 3], 'b': [1, 2, 3]}
d2 = {'a':[4, 5, 6], 'b': [3, 4, 5]}
# make a list of both dictionaries
ds = [d1, d2]
# d will be the resultant dictionary
d = {}
for k in d1.keys():
d[k] = [d[k] for d in ds]
d[k] = list(set([item for sublist in d[k] for item in sublist]))
print(d)
Output
{'a': [1, 2, 3, 4, 5, 6], 'b': [1, 2, 3, 4, 5]}

All possible combinations (including all subsets combinations) of two or more lists

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))

Python: How do I split a list into multiple by comparing its contents?

I have an list such as:
list = [[1, 3, 'orange'], [3, 5, 'apple'], [2, 3, 'orange'], [7, 9, 'pear']]
and i would like to convert it into multiple lists such as:
list1 = [[1, 3, 'orange'], [2, 3, 'orange']]
list2 = [3, 5, 'apple']
list3 = [7, 9, 'pear']
Thank you.
You can iterate over list.
Now check if your filter element is present inside list.
for l in list:
if filter_element in l:
filtered_list1.append(l)
elif condition2:
filtered_list2.append(l)
If you want to do this more aesthetically use can use filter from functools.

sort a list according to keys and for elements with same keys as per values in python

I started learning python recently. I am trying to sort a list of lists similar to this. However, I'm not able to find the correct method to do so please help.
Consider the list [[1,4], [3,3], [3,2] ,[1,2], [1,3], [2,3], [1,5]]
now, using
def keyFunc(j):
return j[0]
job = sorted(job, key=keyFunc, reverse=True)
I got it down to [[all 3s], [all 2s], [all 1s]]
However, now I want to further sort it so that the lists with common keys are in the order of descending values of their keys.
i.e. [[3,3], [3,2], [2,3], [1,5], [1,4], [1,3], [1,2]]
How does one do that in python?
Why do you use a wrong key function when not using a key function already does what you want?
>>> sorted(job, reverse=True)
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
Or since you're assigning back to job anyway, you might want to do job.sort(reverse=True) instead of creating a new list.
You can change the keyFunc to be like
def keyFunc(j):
return j[0]*10+j[1]
or
ls = [[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
sorted(ls, key=lambda x: x[0]*10+x[1], reverse=True)
That will sort both of the numbers as you described.
I think you can just negate the sorting keys to sort descending twice:
>>> lst = [[1,4], [3,3], [3,2] ,[1,2], [1,3], [2,3], [1,5]]
>>> sorted(lst, key=lambda x: (-x[0], -x[1]))
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
(-x[0], -x[1]) will first sort by the first item, then if any ties occur sort on the second item, both in descending manner. We can make it descending by negating with the minus - sign.
But as suggested by #Heap Overflow, we don't need to do this because we can just pass reverse=True, and sorted() will naturally sort by the first item then the second in descending order. No need for a sorting key.
You can test this by running the following:
>>> sorted(lst, reverse=True)
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
>>> sorted(lst, key=lambda x: (x[0], x[1]), reverse=True)
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
Which both give the same results.

Groovy list of lists to map with first list as keys

How would I go in Groovy idiomatically (with collection methods?) from
[['a', 'b', 'c'], [1, 2, 3], [4, 5, 6]]
to
[[a: 1, b: 2, c: 3], [a: 4, b: 5, c: 6]]
def x=[['a', 'b', 'c'], [1, 2, 3], [4, 5, 6]]
x.tail().collect{v-> x.head().indexed().collectEntries{i,k-> [k, v[i]] } }

Resources