Unpack a single element from a list of lists python - python

I have zipped some data into as following:
list1 = [1,33,3]
list2 = [2,44,23]
list3 = [[3,4,5,6],[3,4,5,3],[4,5,3,1]]
list4 = [4,34,4]
data = [list(x) for x in zip(list1, list2, list3, list4)]
However, list3 is a list of lists. So the output ended up being
[[1,2,[3,4,5,6],4],
[33,44,[3,4,5,3],34],
[3,23,[4,5,3,1],4]]
I would like to unpack the list inside the lists like the following:
[[1,2,3,4,5,6,4],
[33,44,3,4,5,3,34],
[3,23,4,5,3,1,4]]
What is the best way to do that in python?
Cheers

If only two level-deep, you can try with first principles:
out = [
[e for x in grp for e in (x if isinstance(x, list) else [x])]
for grp in zip(list1, list2, list3, list4)
]
>>> out
[[1, 2, 3, 4, 5, 6, 4], [33, 44, 3, 4, 5, 3, 34], [3, 23, 4, 5, 3, 1, 4]]

Exploring concepts
First, we have to know what we should do.
The problem is only because list3 is a nested list and this is causing us problems.
To come up with a solution we have to think on how to turn list3 from a nested to a normal list.
To point out:
the shape of list3 is well-defined and it's always the same.
list3 is nested hence we have to think methods to flatten the list.
Finally I come up with 2 possible methods
Flattening list3
I would suggest to flatten list3, using itertools.chain.from_iterable.
chain.from_iterable(iterable)
Alternate constructor for chain(). Gets chained inputs from a single iterable argument that is evaluated lazily.
this can flatten a list of lists.
Here is a possible implementation:
import itertools
list1 = [1,33,3]
list2 = [2,44,23]
list3 = [[3,4,5,6],[3,4,5,3],[4,5,3,1]]
list4 = [4,34,4]
flat_list3 = itertools.chain.from_iterable(list3)
data = [list(x) for x in zip(list1, list2, list3, list4)]
>>> [[1,2,3,4,5,6,4],
[33,44,3,4,5,3,34],
[3,23,4,5,3,1,4]]
Deep nested list flatten
NOTE: This possibility is slower and applicable for nested lists that aren't of a particular shape.
You could use the deepflatten with the map builtin function.
Here is the equivalent to the defined function and arguments.
deepflatten(iterable, depth=None, types=None, ignore=None)
From the docs:
Flatten an iterable with given depth.
>>> from iteration_utilities import deepflatten
>>> data = [[1, 2, [3, 4, 5, 6], 4], [33, 44, [3, 4, 5, 3], 34], [3, 23, [4, 5, 3, 1], 4]]
>>> list(map(lambda x:list(deepflatten(x)),data))
[[1, 2, 3, 4, 5, 6, 4], [33, 44, 3, 4, 5, 3, 34], [3, 23, 4, 5, 3, 1, 4]]
Useful links:
SO(ans) how to find lenght of a list of lists
make a flat list out of lists

Related

Finding common elements from lists in list

I have a list that includes more lists (this is how it looks https://pastebin.com/BW4B9gfa). The number of lists is not constant. I need to create another list that contains only elements that are in all lists in the main list.
I made something like this as a prototype but it doesn't work:
def common_elements(list_of_lists):
lists = list_of_lists
common = lists[0].intersection(lists[1].intersection(lists[2].intersection(lists[3].intersection(lists[4].intersection(lists[5])))))
return common
I see too something like this:
A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))
but I don't know how to use it with bigger number of lists.
You can simply do if you have a list of sets, to get a list of sets just do (lists = [set(list) for list in lists]).
lists[0].intersection(*lists)
You need to convert the first list to a set so you can use the intersection() method.
Use a loop rather than hard-coding all the indexes of the list elements.
def common_elements(lists):
if len(lists) == 0:
return []
common = set(lists[0])
for l in lists[1:]:
common = common.intersection(l)
return list(common)
using functools.reduce():
from functools import reduce
items = [[1, 2, 4], [1, 3, 4], [1, 4, 6], [1, 4, 7, 9]]
eggs = reduce(lambda x, y: set(x) & set(y), items)
print(eggs)
output:
{1, 4}
If you want to get intermediate results, you can use itertools.accumulate()
from itertools import accumulate
items = [[1, 2, 4, 5], [1, 3, 4, 5], [1, 4, 6], [1, 4, 7, 9]]
eggs = list(accumulate(items, func = lambda x, y: set(x) & set(y)))
print(eggs)
output:
[[1, 2, 4, 5], {1, 4, 5}, {1, 4}, {1, 4}]

Quicker way to join multiple lists passed as args to a Python function?

So I have a function which takes a variable number of lists as an argument, then combines those lists into one single list:
def comb_lists(*lists):
sublist = []
for l in lists:
sublist.extend(l)
print(sublist)
>>> comb_lists([1, 2], [3, 4], [5, 6])
[1, 2, 3, 4, 5, 6]
And it works. But I was just wondering if there was a simpler solution? I tried a list comprehension using list unpacking, but that returned a SyntaxError:
def comb_lists(*lists):
sublist = [*l for l in lists]
>>> comb_lists([1, 2], [3, 4], [5, 6])
SyntaxError: iterable unpacking cannot be used in comprehension
Is there any neater or quicker way to do this?
EDIT: itertools looks really useful for this sort of thing. I'd be interested to know if there's any way of doing it that doesn't rely on imports though.
here is the simplest solution
result = sum(lists, [])
There's built-in function chain.form_iterable() in itertools module to do this:
>>> from itertools import chain
>>> my_list = [[1, 2], [3, 4], [5, 6]]
>>> list(chain.from_iterable(my_list))
[1, 2, 3, 4, 5, 6]
If you do not want to import any module, you can write nested list comprehension to achieve this as:
>>> my_list = [[1, 2], [3, 4], [5, 6]]
>>> [e for l in my_list for e in l]
[1, 2, 3, 4, 5, 6]

Slice list based on values in another list

I have long lists, for example:
list1 = ["a","a","b","b","c"]
list2 = [1, 3, 5, 7, 9]`
How can I slice the second list based on the first list (list1 is sorted by its values)?
Like [[1,3],[5,7],[9]]
My lists are very long so I am looking for a fast way to precess this. Thanks!
With itertools.groupby() and a bit of effort.
>>> [[b[1] for b in r] for p,r in itertools.groupby(zip(list1, list2), operator.itemgetter(0))]
[[1, 3], [5, 7], [9]]
Use itertools.izip() instead of zip() if you're running 2.x.
You could also just use a dictionary:
from collections import defaultdict
list1 = ["a","a","b","b","c"]
list2 = [1, 3, 5, 7, 9]
d = defaultdict(list)
for k, v in zip(list1, list2):
d[k].append(v)
>>> print([lst for lst in sorted(d.values())])
[[1, 3], [5, 7], [9]]

function of difference between value

Is there a function in Python to get the difference between two or more values in a list? So, in those two lists:
list1 = [1, 5, 3, 7]
list2 = [4, 2, 6, 4]
I need to calculate the difference between every value in list1 and list2.
for i in list1:
for ii in list2:
print i -ii
This gives negative values, but I want the subtraction between the values of the two lists only from highest value to lowest value for not getting negative values.
For the above lists, I expect the output to be [3, 3, 3, 3].
Thanks.
Assuming you expect [3, 3, 3, 3] as the answer in your question, you can use abs and zip:
[abs(i-j) for i,j in zip(list1, list2)]
Either zip the lists, or use numpy:
>>> list1 = [1, 5, 3, 7]
>>> list2 = [4, 2, 6, 4]
>>> [a-b for a,b in zip(list1, list2)]
[-3, 3, -3, 3]
>>> import numpy as np
>>> np.array(list1) - np.array(list2)
array([-3, 3, -3, 3])
Remember to cast the array back to a list as needed.
edit:
In response to the new requirement that the absolute values are needed: you can add abs in the list comprehension:
>>> [abs(a-b) for a,b in zip(list1, list2)]
[3, 3, 3, 3]
and the numpy solution would change to:
>>> map(abs, np.array(list1) - np.array(list2))
[3, 3, 3, 3]
You may also do if else condition inside list comprehension.
>>> [i-j if i>j else j-i for i,j in zip(list1, list2)]
[3, 3, 3, 3]
You can use zip method in order combine these two lists. See the tutorials for zip method https://docs.python.org/2/library/functions.html#zip
>>> list1 = [1, 5, 3, 7]
>>> list2 = [4, 2, 6, 4]
>>> [abs(x-y) for x, y in zip(list1, list2)]
[3, 3, 3, 3]
Avinash Raj's answer is correct, or alternatively, using map():
from operator import sub
C = map(sub, A, B)

array except other

I have 2 arrays:
arr1 = [a,b,c,d,e]
arr2 = [c,d,e]
I want to give array arr1 except arr2.
Mathematically, you're looking for a difference between two sets represented in lists. So how about using the Python set, which has a builtin difference operation (overloaded on the - operator)?
>>>
>>> arr = [1, 2, 3, 4, 5]
>>> arr2 = [3, 4, 9]
>>> set(arr) - set(arr2)
>>> sdiff = set(arr) - set(arr2)
>>> sdiff
set([1, 2, 5])
>>> list(sdiff)
[1, 2, 5]
>>>
It would be more convenient to have your information in a set in the first place, though. This operation suggests that a set better fits your application semantics than a list. On the other hand, if you may have duplicates in the lists, then set is not a good solution.
So you want the difference of two lists:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list2 = [1, 2, 3, 4, 4, 6, 7, 8, 11, 77]
def list_difference(list1, list2):
"""uses list1 as the reference, returns list of items not in list2"""
diff_list = []
for item in list1:
if not item in list2:
diff_list.append(item)
return diff_list
print list_difference(list1, list2) # [5, 9, 10]
Or using list comprehension:
# simpler using list comprehension
diff_list = [item for item in list1 if item not in list2]
print diff_list # [5, 9, 10]
If you care about (1) preserving the order in which the items appear and (2) efficiency in the case where your lists are large, you probably want a hybrid of the two solutions already proposed.
list2_items = set(list2)
[x for x in list1 if x not in list2_items]
(Converting both to sets will lose the ordering. Using if x not in list2 in your list comprehension will give you in effect an iteration over both lists, which will be inefficient if list2 is large.)
If you know that list2 is not very long and don't need to save every possible microsecond, you should probably go with the simple list comprehension proposed by Flavius: it's short, simple and says exactly what you mean.

Categories

Resources