Related
I have list of lists of lists and need to combine the inner lists accordingly.
For example:
1. mylist=[[[1]], [[2]]]
2.
mylist= [[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
[[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
(in short-[[[1]*3]*4, [[2]*3]*4, [[3]*3]*4])
Expected output-
[[[1, 2]]]
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
(in short-[[[1, 2, 3]]*3]*4)
This is what I have untill now-
def combine_channels(mylist):
elements = [[] for _ in range(len(mylist[0]))]
for l1 in mylist:
for idx, l2 in enumerate(l1):
elements[idx] += l2
return [elements]
The problem is that the output is (for input example 2)-
[[[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3]]]
and not-
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
mylist = [[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
[[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
def combine_channels(mylist):
def list_zip(_list):
return list(zip(*_list))
elements = []
for l in list_zip(mylist):
elements.append(list_zip(l))
return elements
combine_channels(mylist)
This is what i have-
def merge_list(mylist)
list1 = []
one_len = len(mylist)
two_len = len(mylist[0][0])
for index in range(two_len):
combine_list = []
for index2 in range(one_len):
combine_list.extend([a[index] for a in mylist[
index2]])
list1.append(combine_list)
return list1
But i have a problem with the output-
for example:
input-
mylist=[[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]], [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
in short-
[[[1]*3]*4, [[2]*3]*4, [[3]*3]*4]
the output is -
[[[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]]]
and not -
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
in short-
[[[1, 2, 3]]*3]*4
I would be happy to solve the problem and advise how to shorten the code.
In order to fix your code, you just need to update the return statement like this:
return [list1]
Though there is still a hidden problem when your inner lists lengths are longer than one element. Check your outputs with sample inputs like [[[2,1], [3,1]]].
One further - more compact - solution may be obtained by concatenating the inner lists within a cycle, then recreate the number of dimensions you need, moving the complexity from O(n^2) to O(n).
mylist = [[[2,1]],[[3,1]]]
def merge_list(mylist):
l_out = []
for l in mylist:
l_out += l[0]
return [[l_out]]
EDIT: In case of more complex inputs, you can extract first all elements and eventually fix the dimensions. This will still bring O(n^2) complexity though:
def merge_list(lst):
elements = [[] for _ in range(len(mylist[0]))]
for l1 in mylist:
for idx, l2 in enumerate(l1):
elements[idx] += l2
return [elements]
merge_list(mylist)
Input:
[[[1], [1]], [[2], [2]], [[3], [3]]]
Output:
[[[1, 2, 3], [1, 2, 3]]]
I really searched for this one, because I am almost certain some variation has been asked before but I couldn't put in the correct terms into Google to get a result that matches what I am trying to do. Generally seems like people are looking for the total combinations without constraints.
I am trying to do the following:
Given a list like this:
[1, 1, 2, 2, 3, 3] group it into as many groups of [1, 2, 3] as possible
So
[1, 1, 2, 2, 3, 3] -> [[1, 2, 3], [1, 2, 3]]
[1, 1, 2, 3, 3] -> [[1, 2, 3], [1, 3]]
[1, 1, 3, 3, 5] -> [[1, 3, 5], [1, 3]]
[1, 4, 4, 7] -> [[1, 4, 7], [4]]
Notes:
Input will always be sorted, but the values of these numbers is not known, so it will need to work in general sense.
The idea is I have objects with certain attributes that need to be grouped together to create a different object, but sometimes I am given repeats (and potentially incomplete repeats) -- ie, I used to think that the attributes of my objects will always just be [1, 2, 3] but turns out sometimes I can get [1, 1, 2, 2, 3, 3] and I need a way to break that into two [1, 2, 3] lists to create an intermediate object downstream.
You can use zip_longest and groupby from itertools:
from itertools import zip_longest, groupby
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [[j for j in i if j is not None] for i in z]
Usage:
>>> f([1, 1, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3]]
>>> f([1, 1, 2, 3, 3])
[[1, 2, 3], [1, 3]]
>>> f([1, 1, 3, 3, 5])
[[1, 3, 5], [1, 3]]
>>> f([1, 4, 4, 7])
[[1, 4, 7], [4]]
# Update
>>> f(sorted([1, 1, 2, 2, 3, 3, 1, 2]))
[[1, 2, 3], [1, 2, 3], [1, 2]]
# Update 2
>>> f([1, 1, 1, 2, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3], [1, 2]]
Update
Alternative version suggested by #cards using filterfalse:
from itertools import zip_longest, groupby, filterfalse
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [list(filterfalse(lambda j: j is None, i)) for i in z]
My task is to calculate the k-permutations from the updated List by new element
without recalculating the k-permutations already gotten from the previous state of the list. Example:
liste = [1, 2, 3]
3-permutations are:
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
The updated list:
liste = [1, 2, 3, 4]
I would like to obtain directly 3-permutations[1, 2, 3, 4]-3-permutations[1, 2, 3]
without recalculating 3-permutations[1, 2, 3]
Calculate directly the new permutations:
[1, 2, 4], [1, 3, 4], [1, 4, 2], [1, 4, 3], [2, 1, 4], [2, 3, 4], [2, 4, 1],
[2, 4, 3], [3, 1, 4], [3, 2, 4], [3, 4, 1], [3, 4, 2], [4, 1, 2], [4, 1, 3],
[4, 2, 1], [4, 2, 3], [4, 3, 1], [4, 3, 2]
Thanks
Computing first the cartesian product {0,1,2,3}x{0,1,2}x{0,1} and taking the nth element of list (1,2,3,4).
r=[]
for prd in itertools.product([[0,1,2,3],[0,1,2],[0,1]]):
l=[1,2,3,4]
r0=[]
for i in prd:
r0 += l[i]
del l[i]
r += r0
EDIT: original answer gives the 3-permutations of [1,2,3,4]
following command answers specifically to question, see how it can be generalized
[list(j) for i in itertools.combinations([1,2,3],2) for j in itertools.permutations(list(i)+[4])]
next case, maybe one of ?
[list(j) for i in itertools.combinations([1,2,3],2) for j in itertools.permutations(list(i)+[4,5])]
[list(j) for i in itertools.combinations([1,2,3,4],3) for j in itertools.permutations(list(i)+[4,5])]
try saving the existing permutations to a list, then do:
if newPermutation not in listOfExistingPermutations:
listOfExistingPermutations.append(newPermutation)
or something along those lines
I have a 3D list in python like:
features= [ [[1,2,3],[1,2,3],[1,2,3]] ,None , [[1,2,3],[1,2,3],[1,2,3]],
[[1,2,3],[1,2,3],[1,2,3]], None,None,[[1,2,3],[1,2,3],[1,2,3]] ]
I expect to see:
features=[ [[1,2,3],[1,2,3],[1,2,3]] ,[[1,2,3],[1,2,3],[1,2,3]],
[[1,2,3],[1,2,3],[1,2,3]] ,[[1,2,3],[1,2,3],[1,2,3]] ]
When I try to remove None using the following code:
for i in range(len(features)):
if features[i]==None:
features[i].remove()
It produces the error :
AttributeError: 'NoneType' object has no attribute 'remove'
If I try this:
for i in range(len(features)):
if features[i]==None:
del features[i]
It produces error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Lastly I tried this code:
for i in range(len(features)):
if features[i]==None:
features[i]=filter(None,features[i])
It produced the error :-
TypeError: 'NoneType' object is not iterable
How can I fix this error?
In your first code block, you are not passing a value to be removed from the list. In the second code block, you are altering the list while iterating, thus producing a skewed index-vs-value location. The best way is to filter out the Nones from the list:
features= [ [[1,2,3],[1,2,3],[1,2,3]] ,None , [[1,2,3],[1,2,3],[1,2,3]],
[[1,2,3],[1,2,3],[1,2,3]], None,None,[[1,2,3],[1,2,3],[1,2,3]] ]
final_features = list(filter(lambda x:x is not None, features))
Output:
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
Create a list comprehension and only keep the values if the index is not None, it will keep your sub-lists intact:
features = [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
>>> print features
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
>>> print [f for f in features if f is not None]
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
Short and simple:
features_x = list(filter(None, features))
print(features_x)
See a demo on ideone.com.
Like willem says you should never alter a list that you're iterating over. The correct way of doing is to create a new list. You can do that with a list comprehension in the following way.
New = [item for item in mylist if item is not None]
You could also try it this way:
new_features = []
for f in features:
if f is not None:
new_features.append(f)
You can also just index through the array backwards when you do your features[i].remove().
for i in reversed(range(len(features))):
if features[i]==None:
features[i].remove()
This way you are not removing array items out from underneath your index.
The other answers are slick-code, no doubt, but this is the easiest simple-code solution.
Of course, you should never alter a list you are iterating through as a general best-practice, but when you absolutely have to keep using the same list, this will work.