Unnesting List Function [duplicate] - python

This question already has answers here:
Flatten an irregular (arbitrarily nested) list of lists
(51 answers)
Closed 1 year ago.
Trying to unnest this list: [1, [2, 3, [4, 5, [6]]], [7, 8], 9]
Into this list: [1, 2, 3, 4, 5, 6, 7, 8, 9]
So far this is my function:
L = [1, [2, 3, [4, 5, [6]]], [7, 8], 9]
def unnesting(L):
my_list = []
for element in (L):
if type(element) is list:
my_list.extend(element)
else:
my_list.append(element)
return my_list
except it gives me this output: [1, 2, 3, [4, 5, [6]], 7, 8, 9]
Any solutions or advice on how to unnest this list? Thank you!

You need recursion, otherwise, the function will only work for a nested depth of 2. The important realization is that when your list contains a list again, then you are facing the same problem, i.e. can call the same function again.
The following will work:
L = [1, [2, 3, [4, 5, [6]]], [7, 8], 9]
def unnest(lst1, lst2=None):
if lst2 is None:
lst2 = []
for x in lst1:
if not isinstance(x, list):
lst2.append(x)
else:
unnest(x, lst2)
return lst2
flattened = unnest(L)
print(flattened)

I think you're just looking for a short recursive solution here, try this:
L = [1, [2, 3, [4, 5, [6]]], [7, 8], 9]
def unnesting(my_list):
if type(my_list) == int:
return [my_list]
return sum((unnesting(elem) for elem in my_list), [])
print(unnesting(L))
Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
If you have any questions about how this works, leave a comment below and I'll do my best to help you understand.

You can try this. I have just called the function recursively.
my_list = []
def unnesting(L):
for element in L:
if type(element) is list:
unnesting(element)
else:
my_list.append(element)
return my_list

well this is a little different way of doing this. I don't recommend doing it this way. But python allows us to get the result multiple ways.
def unnest(lst):
_ = str(lst)
_ = _.replace('[', '').replace(']', '').replace(',', '').replace(' ', '')
return [int(i) for i in _]
L = [1, [2, 3, [4, 5, [6]]], [7, 8], 9]
unnest(L)

Related

List comprehension headaches

I have a nested list like this which:
list = [[1,2,3], [2,5,7,6], [1,-1], [5,7], [6,3,7,4,3], [2, 5, 1, -5]]
What I am trying to do is to remove nested lists, where the value within these lists are both positive and negative. I have tried doing it by list comprehension, but I couldn't figure it out.
def method(list):
return [obj for obj in list if (x for x in obj if -x not in obj)]
The obtained results should be like:
list = [[1,2,3], [2,5,7,6], [5,7], [6,3,7,4,3]]
Assuming you want lists where elements are either all negative or all positive you can use all predefined function to check for both possibilities
result = [L for L in x if all(y>0 for y in L) or all(y<0 for y in L)]
EDIT:
In the comments you clarified what is a valid list (e.g. [-1, 2] is valid)... with this new formulation the test should be
result = [L for L in x if all(-y not in L for y in L)]
where each single test is however now quadratic in the size of the list. Using set this problem can be removed
result = [L for L in x if all(-y not in S for S in (set(L),) for y in L)]
Using list comprehension you can do something like:
def method2(list):
return [obj for obj in list if (all(n>0 for n in obj) or all(n<0 for n in obj))]
that, with your example, give as output:
[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
In general is better to split the task by steps:
Given list find the positives (positives function)
Given list find the negatives and multiply them by -1 (negatives function)
If the intersection of both positives and negatives is not empty remove.
So, you could do:
def positives(ls):
return set(l for l in ls if l > 0)
def negatives(ls):
return set(-1*l for l in ls if l < 0)
list = [[1, 2, 3], [2, 5, 7, 6], [1, -1], [5, 7], [6, 3, 7, 4, 3], [2, 5, 1, -5]]
result = [l for l in list if not negatives(l) & positives(l)]
print(result)
Output
[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
As a side note you should not use list as a variable name as it shadows the built-int list function.
Your generator should yield whether the condition to filter an object applies.
You then feed the generator to an aggregator to determine if obj should be filtered.
the aggregator could be any or all, or something different.
# assuming obj should be filtered if both x and the inverse of x are in obj
def method_with_all(src):
return [obj for obj in src if all(-x not in obj for x in obj)]
def method_with_any(src):
return [obj for obj in src if any(-x in obj for x in obj)]
you can filter out the lists that have both negative and positive elements:
def keep_list(nested_list):
is_first_positive = nested_list[0] > 0
for element in nested_list[1:]:
if (element > 0) != is_first_positive:
return False
return True
my_list = [[1,2,3], [2,5,7,6], [1,-1], [5,7], [6,3,7,4,3], [2, 5, 1, -5]]
print(list(filter(keep_list, my_list)))
output:
[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
Numpy can be used as well. My solution here is similar to the "all"-operation suggested by others but coded explicitly and only needs one condition. It checks whether the sign of the all the elements equals the sign of the first element (could be any other as well).
from numpy import *
def f(b):
return [a for a in b if sum(sign(array(a)) == sign(a[0])) == len(a)]
For your case...
data = [[1,2,3], [2,5,7,6], [1,-1], [5,7], [6,3,7,4,3], [2, 5, 1, -5]]
print(f(data))
...it will return:
[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]

Concatenate pairs of consecutive sublists in a list using Python

How would you combine sublists within a list by pairs?
For example with:
list1 = [[1,2,3],[4,5],[6],[7,8],[9,10]]
the result would be:
[[1,2,3,4,5],[6,7,8],[9,10]]
You could use zip_longest with a fill value (in case your list has an odd number of sublists) to zip an iterator over list1. Running a list comprehension over the zip generator object allows you to concatenate the consecutive pairs of lists:
>>> from itertools import zip_longest # izip_longest in Python 2.x
>>> x = iter(list1)
>>> [a+b for a, b in zip_longest(x, x, fillvalue=[])]
[[1, 2, 3, 4, 5], [6, 7, 8], [9, 10]]
Try using a list comprehension (but be careful with the indexes!). It works for lists with an even or odd number of sublists:
list1 = [[1, 2, 3], [4, 5], [6], [7, 8], [9, 10]]
n = len(list1)
[list1[i] + (list1[i+1] if i+1 < n else []) for i in xrange(0, n, 2)]
=> [[1, 2, 3, 4, 5], [6, 7, 8], [9, 10]]
list1=[[1,2,3],[4,5],[6],[7,8],[9,10]]
length = len(list1)
new_list = [ list1[i]+list1[i+1] if i+1 < length
else [list1[i]] for i in range(0,length,2) ]
print(new_list)
>>> list1=[[1,2,3],[4,5],[6],[7,8],[9,10]]
>>> list1
[[1, 2, 3], [4, 5], [6], [7, 8], [9, 10]]
Now we can do:
>>> test = [list1[0]+list1[1]]+[list1[2]+list1[3]]+list1[4]
>>> test
[[1, 2, 3, 4, 5], [6, 7, 8], 9, 10]
>>>
I am sure there is a better way, but this is the way I can think of!
list1 = [[1, 2, 3], [4, 5], [6], [7, 8], [9, 10]]
from itertools import islice, chain
print([list(chain.from_iterable(islice(list1, i, i + 2)))
for i in range(0, len(list1), 2)])
[[1, 2, 3, 4, 5], [6, 7, 8], [9, 10]]
Or without islice:
print([list(chain.from_iterable(list1[i:i+2]))
for i in range(0, len(list1), 2)])
[[1, 2, 3, 4, 5], [6, 7, 8], [9, 10]]
Use a simple loop:
list1=[[1,2,3],[4,5],[6],[7,8],[9,10]]
newlist = []
for i in range(0, len(list1), 2):
newlist.append(list1[i] + list1[i+1])
if len(list1) % 2 > 0:
newlist.append(list1[-1])
print newlist
Here is (I hope) a correct solution:
def pair_up(ls):
new_list = []
every_other1 = ls[::2]
every_other2 = ls[1::2]
for i in range(len(every_other2)):
new_list.append(every_other1[i]+every_other2[i])
if len(ls) % 2 == 1:
new_list.append(ls[-1])
return new_list
Working on same list with removing n-ths[-1] odd sublists:
for i in range(len(l)/2):#here we go only to last even item
l[i]+=l[i+1]#adding odd sublist to even sublist
l.pop(i+1)#removing even sublist

Why the results are different from using merge(lista+listb) [duplicate]

This question already has answers here:
(Python) adding a list to another without the brackets
(3 answers)
Closed 7 years ago.
Here I'm trying to merge this two lists, making one whit all items.
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
def flatten(n):
s=[]
for x in n:
s.append(x)
return s
print flatten(n)
I'm trying to have as a result
[1,2,3,4,5,6,7,8,9]
but I'm getting
[[1, 2, 3], [4, 5, 6, 7, 8, 9]]
I dont understand why, I think I'm clearly assigning each value to the list 's' in the for loop.
You're appending to the list. Each sublist is appended to the new list as its own item, exactly the way it was originally. You want to extend the list instead:
s.extend(x)
Use extend, instead of append
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
def flatten(n):
s=[]
for x in n:
s.extend(x)
return s
print flatten(n)
Best of luck.
You should be using list.extend, append is appending each sublist not adding just the contents. x is each sublist so just appending the sublist is obviously going to give you a list of lists again.
You can also use itertools.chain to flatten the list:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
print(list(chain.from_iterable(n)))
Or use a list comp:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
print([ele for sub in n for ele in sub])

concatenating sublists python [duplicate]

This question already has answers here:
How do I make a flat list out of a list of lists?
(34 answers)
Closed 9 years ago.
I have one list like:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
I want to create a function that takes a single list (see above) and concatenates all the sublists that are part of it into a single list.
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
nn = [ x for y in n for x in y]
>>> lst = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
>>> from itertools import chain
>>> list(chain.from_iterable(lst))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
For completeness, here is a very short way to write this
>>> sum(n, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
But although it is tempting, you shouldn't because it has quadratic performance. ie a new list is created as each term is added, and all the previous items will be copied over and over
It's ok to use list.extend though
reduce(lambda x,y: x.extend(y) or x, n, [])
You can also concatenate by doing simply:
print n[0]+n[1]
In general this would be:
def concatenate(list):
x=[]
for i in list:
x+=i
return x
But this is not particularly efficent, just quite straightforward for a beginner.

How can I get a set of (possibly overlapping) slices in a Python list based on elements that match a criteria?

Suppose I have a python list l=[1,2,3,4,5]. I would like to find all x-element lists starting with elements that satisfy a function f(e), or the sublist going to the end of l if there aren't enough items. For instance, suppose f(e) is e%2==0, and x=3 I'd like to get [[2,3,4],[4,5]].
Is there an elegant or "pythonic" way to do this?
>>> f = lambda e: e % 2 == 0
>>> x = 3
>>> l = [1, 2, 3, 4, 5]
>>> def makeSublists(lst, length, f):
for i in range(len(lst)):
if f(lst[i]):
yield lst[i:i+length]
>>> list(makeSublists(l, x, f))
[[2, 3, 4], [4, 5]]
>>> list(makeSublists(list(range(10)), 5, f))
[[0, 1, 2, 3, 4], [2, 3, 4, 5, 6], [4, 5, 6, 7, 8], [6, 7, 8, 9], [8, 9]]
Using a list comprehension:
>>> l = range(1,6)
>>> x = 3
>>> def f(e):
return e%2 == 0
>>> [l[i:i+x] for i, j in enumerate(l) if f(j)]
[[2, 3, 4], [4, 5]]

Categories

Resources