I have a nested list in the following form
inputlist = [[1,2,3],[4,5,6],[7,8,9],[1,2,3,4],[5,6,7,8],[1,2],[3,4]]
I would like further nest it based on changing length as follows:
outputlist = [[[1,2,3],[4,5,6],[7,8,9]],[[1,2,3,4],[5,6,7,8]],[[1,2],[3,4]]]
The underlying logic is that I wish to group every change in list length into a new sublist. It is kind of difficult to explain but I hope the above two examples show what I am trying to do.
How can I achieve this simply and elegantly using python? Thanks.
>>> from itertools import groupby
>>> input_list = [[1,2,3],[4,5,6],[7,8,9],[1,2,3,4],[5,6,7,8],[1,2],[3,4]]
>>> [list(g) for k, g in groupby(input_list, key=len)]
[[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[1, 2, 3, 4], [5, 6, 7, 8]], [[1, 2], [3, 4]]]
Here's an approach.
Get a list of the lengths involved:
#solen: set of lengths
solen = set([len(subl) for subl in inputlist]) # portable
solen = {len[subl] for subl in inputlist} # post Python 2.6
Then build the list of lists of a particular length:
#losubl: list of sublists, one for each item from solen
losubl = [[subl for subl in inputlist if len(subl) == ulen] for ulen in solen]
As jamylak points out, this solution is less efficient than the one based on itertools (more than one pass, sacrifices some order information). OTOH, it may avoid an import if you don't have other uses for itertools. If the lists you're working with are big and complicated, it's probably worth the extra import to use itertools.
Related
I am trying to average numbers of different lists of varying lengths. (in nested-list form as shown below)
mylist =[[1, 3, 7, 10], [3, 9, 9, 0], [5, 6]]
I want the result of
averaged_list = [3, 6, 8, 5]
I have tried,
averaged_list = [mean(x) for x in zip(*mylist)]
which only lends:
[3, 6]
mylist above is simplified just to demonstrate the purpose but it will be lengthier in practice.
Thank you for the help and advice!
zip will ignore excess values according to the shortest length iterable. You must use itertools.zip_longest instead, and must take care of filtering the None fill-values:
import itertools
averaged_list = [
mean((x for x in xs if x is not None)) # ignore fillvalues
for xs in itertools.zip_longest(*mylist)
]
You could do this:
from itertools import zip_longest
import numpy as np
averaged_list = [np.nanmean(x) for x in zip_longest(*mylist, fillvalue=np.nan)]
(See #michaeldel's answer for explanation, same idea)
How do I add elements of lists within a list component wise?
p=[[1,2,3],[1,0,-1]]
I have tried the following:
list(map(sum,zip(p[0],p[1])))
Will get me [2,2,2] which is what I need. But how to extend it for a variable number of lists? For example, p=[[1,2,3],[1,0,-1],[1,1,1]] should yield [3,3,3].
A solution I figured out is the following:
import pandas as pd
p=[[1,2,3],[1,0,-1],[1,1,1]]
list(pd.DataFrame(p).sum())
Is there a more "Pythonic" way to solve this problem?
Use * for unpack lists:
a = list(map(sum,zip(*p)))
print (a)
[3, 3, 3]
In numpy solution is similar like in pandas:
a = np.array(p).sum(axis=0).tolist()
print(a)
[3, 3, 3]
You can use * to unpack the list and sum to sum it up.
If you are uncomfortable with the map function you can do it like this:
p = [[1, 2, 3], [4, 5, 6], [-5,-7,-9]]
sum_list = [sum(elem) for elem in zip(*p)]
print(sum_list)
I have a nested list as an example:
lst_a = [[1,2,3,5], [1,2,3,7], [1,2,3,9], [1,2,6,8]]
I'm trying to check if the first 3 indices of a nested list element are the same as other.
I.e.
if [1,2,3] exists in other lists, remove all the other nested list elements that contain that. So that the nested list is unique.
I'm not sure the most pythonic way of doing this would be.
for i in range(0, len(lst_a)):
if lst[i][:3] == lst[i-1][:3]:
lst[i].pop()
Desired output:
lst_a = [[1,2,3,9], [1,2,6,8]]
If, as you said in comments, sublists that have the same first three elements are always next to each other (but the list is not necessarily sorted) you can use itertools.groupby to group those elements and then get the next from each of the groups.
>>> from itertools import groupby
>>> lst_a = [[1,2,3,5], [1,2,3,7], [1,2,3,9], [1,2,6,8]]
>>> [next(g) for k, g in groupby(lst_a, key=lambda x: x[:3])]
[[1, 2, 3, 5], [1, 2, 6, 8]]
Or use a list comprehension with enumerate and compare the current element with the last one:
>>> [x for i, x in enumerate(lst_a) if i == 0 or lst_a[i-1][:3] != x[:3]]
[[1, 2, 3, 5], [1, 2, 6, 8]]
This does not require any imports, but IMHO when using groupby it is much clearer what the code is supposed to do. Note, however, that unlike your method, both of those will create a new filtered list, instead of updating/deleting from the original list.
I think you are missing a loop For if you want to check all possibilities. I guess it should like :
for i in range(0, len(lst_a)):
for j in range(i, len(lst_a)):
if lst[i][:3] == lst[j][:3]:
lst[i].pop()
Deleting while going throught the list is maybe not the best idea you should delete unwanted elements at the end
Going with your approach, Find the below code:
lst=[lst_a[0]]
for li in lst_a[1:]:
if li[:3]!=lst[0][:3]:
lst.append(li)
print(lst)
Hope this helps!
You can use a dictionary to filter a list:
dct = {tuple(i[:3]): i for i in lst}
# {(1, 2, 3): [1, 2, 3, 9], (1, 2, 6): [1, 2, 6, 8]}
list(dct.values())
# [[1, 2, 3, 9], [1, 2, 6, 8]]
I am a python beginner--headbangin'. This is a very basic question and I can't seem to find any straight forward answer, either using google or StackOverFlow.
QUESTION:
I have a nested list:
l = [
[1,4,3,n]
[2,2,4,n]
[3,1,5,n]
]
I want to sort the entire list by the second value smallest to largest. I will end up sorting the list again by the third value... and nth value of each nested list.
HOW WOULD ONE SORT based on the SECOND, THIRD, Nth value?
A key is mentioned, but "key=lambda" is often used and that just confuses me more.
EDIT: Thank you guys for your help. I was able to use your advice to solve the problem at hand. I would upvote you but apparently, I can't yet show my thanks in that form. I will return someday and give you your reputation bumps.
Can also be done using operator
Inside operator.itemgetter(1) you are indicating which index you want to sort on. So, in in this case we are specifying 1 which is the second item.
import operator
l = [[1,4,3], [2,2,4], [3,1,5]]
print(sorted(l, key=operator.itemgetter(1)))
output:
[[3, 1, 5], [2, 2, 4], [1, 4, 3]]
You can try like this,
>>> l = [[1,4,3], [2,2,4], [3,1,5]]
>>> sorted(l, key=lambda x: x[1])
[[3, 1, 5], [2, 2, 4], [1, 4, 3]]
or:
>>> l.sort(key=lambda x: x[1])
>>> l
[[3, 1, 5], [2, 2, 4], [1, 4, 3]]
vals= [1]
for j in xrange(i):
vals.append([k for k in f(vals[j])])
This loop appends values to itself over a loop. If I compress this into a list comprehension, it doesn't work because it doesn't "dynamically" extend vals using itself on each iteration -- it processes vals as it is originally framed.
Is there a way to do a one line list comprehension that dynamically appends like this? Based on my research, it looks like maybe I am looking for a reduce function? (the equivalent of a fold)
You can indeed use reduce for this, using the initial list as the third parameter.
>>> def f(lst):
... return [x+1 for x in lst] + [len(lst)]
>>> reduce(lambda lst, i: lst + [f(lst[i])], range(5), [[1]])
[[1], [2, 1], [3, 2, 2], [4, 3, 3, 3], [5, 4, 4, 4, 4], [6, 5, 5, 5, 5, 5]]
(Note that the initial list should probably be [[1]], not [1], otherwise you are passing a number to f in the first iteration, but a list in all following iterations.)
Also note that concerning performance your original loop is probably a bit faster, as the reduce basically has to create two new lists in each iteration, while you just have to append to a list. Personally, I would go with a variation of the loop, removing the (probably useless) inner list comprehension and using [-1] to make clear that you are always using the previous result.
vals = [[1]]
for _ in xrange(n):
vals.append(f(vals[-1]))