Creating a nested list inside a nested list in python - python

I have this nested list:
list_1 = [[1,2,3], [1,2,3,4,5,6], [1,2,3,4,5,6,7,8,9]]
Count of sublist elements are always in mulitple of 3. I want to have 3 elments in each sublist. Desired output:
list_1 = [[1,2,3], [1,2,3], [4,5,6],[1,2,3], [4,5,6], [7,8,9]]
I can achieve this but first i have to flatten the list and then create the nested list. My code:
list_1 = [values for sub_list in lists_1 for values in sub_list] # flatten it first
list_1 = [list_1[i:i+3] for i in range(0, len(list_1), 3)]
Is there a way to skip the flatten step and get the desired result?

You can use a nested list comprehension:
list_1 = [[1,2,3], [1,2,3,4,5,6], [1,2,3,4,5,6,7,8,9]]
result = [i[j:j+3] for i in list_1 for j in range(0, len(i), 3)]
Output:
[[1, 2, 3], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6], [7, 8, 9]]

Here is how you can use nested list comprehensions:
list_1 = [[1,2,3],[1,2,3,4,5,6],[1,2,3,4,5,6,7,8,9]]
list_1 = [a for b in list_1 for a in b]
list_1 = [list_1[i:i+3] for i in range(0,len(list_1),3)]
print(list_1)
Output:
[[1, 2, 3], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6], [7, 8, 9]]

To put my two cents in, you could use two generator functions, one that flattens the list (with an arbitrarly nested list) and one that yields pairs of n values:
def recursive_yield(my_list):
for item in my_list:
if isinstance(item, list):
yield from recursive_yield(item)
else:
yield item
def taken(gen, number = 3):
buffer = []
for item in gen:
if len(buffer) < number:
buffer.append(item)
else:
yield buffer
buffer = []
buffer.append(item)
if buffer:
yield buffer
result = [x for x in taken(recursive_yield(list_1))]
Here are some examples of the in- / outputs:
list_1 = [[1,2,3], [1,2,3,4,5,6], [1,2,3,4,5,6,7,8,9]]
# -> [[1, 2, 3], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
list_1 = [1,2,3,4,5,6]
# -> [[1, 2, 3], [4, 5, 6]]
list_1 = [1,2,[[1,2,4,5], [[[[1,10,9]]]]]]
# -> number = 5
# -> [[1, 2, 1, 2, 4], [5, 1, 10, 9]]
Thus, the solution is much more flexible than slicing alone.

Related

How to extract elements from a nested list

I have a nested list in the form of [[1,2,3], [3,4,5], [8,6,2,5,6], [7,2,9]]
I would like to extract every first item into a new list, every second item into a new list and the rest into a new nested list:
a = [1,3,8,7] b = [2,4,6,2], c = [[3], [5], [2,5,6],[9]]
Is it possible to avoid using the for loop because the real nested list is quite large? Any help would be appreciated.
Ultimately, whatever your solution would be, you're gonna have to have a for loop inside your code and my advice would be to make it as clean and as readable as possible.
That being said, here's what I would propose:
arr = [[1,2,3], [3,4,5], [8,6,2,5,6], [7,2,9]]
first_arr, second_arr, third_arr = [], [], []
for nested in arr:
first_arr.append(nested[0])
second_arr.append(nested[1])
third_arr.append(nested[2:])
This is a naive, simple looped solution using list comprehensions, but see if it is fast enough for you.
l = [[1,2,3], [3,4,5], [8,6,2,5,6], [7,2,9]]
a = [i[0] for i in l]
b = [i[1] for i in l]
c = [i[2:] for i in l]
which returns:
>>a
[1, 3, 8, 7]
>>b
[2, 4, 6, 2]
>>c
[[3], [5], [2, 5, 6], [9]]
At the moment I cannot think a solution without for loops, I hope I will be able to update my answer later.
Here's a solution using for loops:
data = [[1,2,3], [3,4,5], [8,6,2,5,6], [7,2,9]]
list1 = []
list2 = []
list3 = []
for item in data:
else_list = []
for index, value in enumerate(item):
if index == 0:
list1.append(value)
elif index == 1:
list2.append(value)
else:
else_list.append(value)
list3.append(else_list)
print(list1)
print(list2)
print(list3)
Output
[1, 3, 8, 7]
[2, 4, 6, 2]
[[3], [5], [2, 5, 6], [9]]
Just for fun I share also a performance comparison, great job in using just one for loop Meysam!
import timeit
# a = [1,3,8,7] b = [2,4,6,2], c = [[3], [5], [2,5,6],[9]]
def solution_1():
data = [[1, 2, 3], [3, 4, 5], [8, 6, 2, 5, 6], [7, 2, 9]]
list1 = []
list2 = []
list3 = []
for item in data:
else_list = []
for index, value in enumerate(item):
if index == 0:
list1.append(value)
elif index == 1:
list2.append(value)
else:
else_list.append(value)
list3.append(else_list)
def solution_2():
arr = [[1, 2, 3], [3, 4, 5], [8, 6, 2, 5, 6], [7, 2, 9]]
first_arr, second_arr, third_arr = [], [], []
for nested in arr:
first_arr.append(nested[0])
second_arr.append(nested[1])
third_arr.append(nested[2:])
def solution_3():
l = [[1, 2, 3], [3, 4, 5], [8, 6, 2, 5, 6], [7, 2, 9]]
a = [i[0] for i in l]
b = [i[1] for i in l]
c = [i[2:] for i in l]
if __name__ == "__main__":
print("solution_1 performance:")
print(timeit.timeit("solution_1()", "from __main__ import solution_1", number=10))
print("solution_2 performance:")
print(timeit.timeit("solution_2()", "from __main__ import solution_2", number=10))
print("solution_3 performance:")
print(timeit.timeit("solution_3()", "from __main__ import solution_3", number=10))
Output
solution_1 performance:
9.580000000000005e-05
solution_2 performance:
1.7200000000001936e-05
solution_3 performance:
1.7499999999996685e-05
Suppose the nested list has unknown depth, then we'd have to use recursion
def get_elements(l):
ret = []
for elem in l:
if type(elem) == list:
ret.extend(get_elements(elem))
else:
ret.append(elem)
return ret
l = [1,2,[3,4],[[5],[6]]]
print(get_elements(l))
# Output: [1, 2, 3, 4, 5, 6]
Though it is not quite recommended to use unknown-depth nested lists in the first place.

append list of lists in python

I am trying to append a list of lists with Python but there is an error. My problem is just with append function. I explain my problem better. I am using a loop. The first time the append function works fine. But for the second time, the function does not work.
When we do the first loop, we get the right result:
list1 = [1,2,3]
list2 = [4,5,6]
list3 = []
list3.append(list1)
list3.append(list2)
print(list3)
result:
[[1, 2, 3], [4, 5, 6]]
With the second loop, append does not work correctly. One extra bracket.
liste4 = []
liste4.append(list3)
liste4.append(list1)
print(liste4)
result:
[[[1, 2, 3], [4, 5, 6]], [1, 2, 3]]
But the result I want is this:
[[1, 2, 3], [4, 5, 6], [1, 2, 3]]
Define list3 as an empty list and append to it :
list1 = [1,2,3]
list2 = [4,5,6]
list3 = []
list3.append(list1)
list3.append(list2)
print(list3)
Output :
[[1, 2, 3], [4, 5, 6]]
you could just do list3 = [list1, list2]
If you want it in a function, here is a go a a List of List creator, which may take multiple lists as the input:
def LoL(*lists):
out = [x for x in lists]
return out
list1 = [1,2,3]
list2 = [4,5,6]
list3 = [7,8,9]
list4 = LoL(list1,list2,list3)
list4
>>> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
list1 = [1,2,3]
list2 = [4,5,6]
list3 = []
list3.append(list1)
list3.append(list2)
print(list3)
result:
[[1, 2, 3], [4, 5, 6]]
With the second loop:
liste4 = list3
liste4.append(list1)
print(liste4)
result:
[[1, 2, 3], [4, 5, 6], [1, 2, 3]]

How to do Math Functions on Lists within a List

I'm very new to python (using python3) and I'm trying to add numbers from one list to another list. The only problem is that the second list is a list of lists. For example:
[[1, 2, 3], [4, 5, 6]]
What I want is to, say, add 1 to each item in the first list and 2 to each item in the second, returning something like this:
[[2, 3, 4], [6, 7, 8]]
I tried this:
original_lst = [[1, 2, 3], [4, 5, 6]]
trasposition_lst = [1, 2]
new_lst = [x+y for x,y in zip(original_lst, transposition_ls)]
print(new_lst)
When I do this, I get an error
can only concatenate list (not "int") to list
This leads me to believe that I can't operate in this way on the lists as long as they are nested within another list. I want to do this operation without flattening the nested list. Is there a solution?
One approach using enumerate
Demo:
l = [[1, 2, 3], [4, 5, 6]]
print( [[j+i for j in v] for i,v in enumerate(l, 1)] )
Output:
[[2, 3, 4], [6, 7, 8]]
You can use enumerate:
l = [[1, 2, 3], [4, 5, 6]]
new_l = [[c+i for c in a] for i, a in enumerate(l, 1)]
Output:
[[2, 3, 4], [6, 7, 8]]
Why don't use numpy instead?
import numpy as np
mat = np.array([[1, 2, 3], [4, 5, 6]])
mul = np.array([1,2])
m = np.ones(mat.shape)
res = (m.T *mul).T + mat
You were very close with you original method. Just fell one step short.
Small addition
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
new_lst = [[xx + y for xx in x] for x, y in zip(original_lst, transposition_lst)]
print(new_lst)
Output
[[2, 3, 4], [6, 7, 8]]
Reasoning
If you print your original zip it is easy to see the issue. Your original zip yielded this:
In:
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
for x,y in zip(original_lst, transposition_lst):
print(x, y)
Output
[1, 2, 3] 1
[4, 5, 6] 2
Now it is easy to see that you are trying to add an integer to a list (hence the error). Which python doesn't understand. if they were both integers it would add them or if they were both lists it would combine them.
To fix this you need to do one extra step with your code to add the integer to each value in the list. Hence the addition of the extra list comprehension in the solution above.
A different approach than numpy that could work even for lists of different lengths is
lst = [[1, 2, 3], [4, 5, 6, 7]]
c = [1, 2]
res = [[l + c[i] for l in lst[i]] for i in range(len(c))]

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

Un-nesting nested lists

Hi I was wondering how I could un-nest a nested nested list. I have:
list = [[[1,2,3]], [[4,5,6]], [[7,8,9]]]
I would like to to look as follows:
new_list = [[1,2,3], [4,5,6], [7,8,9]]
How to do it?
>>> L = [[[1,2,3]], [[4,5,6]], [[7,8,9]]]
>>> [x[0] for x in L]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
For multiple nestings:
def unnesting(l):
_l = []
for e in l:
while isinstance(e[0], list):
e = e[0]
_l.append(e)
return _l
A test:
In [24]: l = [[[1,2,3]], [[[[4,5,6]]]], [[[7,8,9]]]]
In [25]: unnesting(l)
Out[25]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
I found another solution that might be easier and quicker here and also mentioned here.
from itertools import chain
nested_list = [[[1,2,3]], [[4,5,6]], [[7,8,9]]]
my_unnested_list = list(chain(*nested_list))
print(my_unnested_list)
which results in your desired output as:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Categories

Resources