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.
Related
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)
I'm using Python 2.7 and have the following:
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
I'd like create a 1-d list where the elements are ordered by position in sublist and then order of sublist. So the correct output for the above list is:
[1, 4, 7, 2, 5, 8, 3, 6, 9]
Here's my (incorrect) attempt:
def reorder_and_flatten(my_list):
my_list = [item for sublist in my_list for item in sublist]
result_nums = []
for i in range(len(my_list)):
result_nums.extend(my_list[i::3])
return result_nums
result = reorder_and_flatten(my_list)
This flattens my 2-d list and gives me:
[1, 4, 7, 2, 5, 8, 3, 6, 9, 4, 7, 5, 8, 6, 9, 7, 8, 9]
The first half of this list is correct but the second isn't.
I'd also like my function to be able to handle only 2 sublists. For instance, if given:
[[1, 2, 3], [], [7, 8, 9]
the correct output is:
[1, 7, 2, 8, 3, 9]
Any thoughts?
Thanks!
You're attempting to flatten, and then reorder, which makes things a lot harder than reordering and then flattening.
First, for your initial problem, that's just "unzip", as explained in the docs for zip:
>>> my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> list(zip(*my_list))
... [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
(In Python 2.7, you could just write zip(…) here instead of list(zip(…)), but this way, the same demonstration works identically in both 2.x and 3.x.)
And then, you already know how to flatten that:
>>> [item for sublist in zip(*my_list) for item in sublist]
[1, 4, 7, 2, 5, 8, 3, 6, 9]
But things get a bit more complicated for your second case, where some of the lists may be empty (or maybe just shorter?).
There's no function that's like zip but skips over missing values. You can write one pretty easily. But instead… there is a function that's like zip but fills in missing values with None (or anything else you prefer), izip_longest. So, we can just use that, then filter out the None values as we flatten:
>>> my_list = [[1, 2, 3], [], [7, 8, 9]]
>>> from itertools import izip_longest
>>> list(izip_longest(*my_list))
[(1, None, 7), (2, None, 8), (3, None, 9)]
>>> [item for sublist in izip_longest(*my_list) for item in sublist if item is not None]
[1, 7, 2, 8, 3, 9]
(In Python 3, the function izip_longest is renamed zip_longest.)
It's worth noting that the roundrobin recipe, as covered by ShadowRanger's answer, is an even nicer solution to this problem, and even easier to use (just copy and paste it from the docs, or pip install more_itertools and use it from there). It is a bit harder to understand—but it's worth taking the time to understand it (and asking for help if you get stuck).
result = [l[i] for i in range(max(len(v) for v in my_list)) for l in my_list if l]
i.e.
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[l[i] for i in range(max(len(v) for v in my_list)) for l in my_list if l]
# => [1, 4, 7, 2, 5, 8, 3, 6, 9]
my_list = [[1, 2, 3], [], [7, 8, 9]]
[l[i] for i in range(max(len(v) for v in my_list)) for l in my_list if l]
# => [1, 7, 2, 8, 3, 9]
The itertools module's recipes section provides a roundrobin recipe that would do exactly what you want. It produces a generator, but your expected behavior would be seen with:
# define roundrobin recipe here
from itertools import cycle, islice
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
pending = len(iterables)
nexts = cycle(iter(it).next for it in iterables)
while pending:
try:
for next in nexts:
yield next()
except StopIteration:
pending -= 1
nexts = cycle(islice(nexts, pending))
def reorder_and_flatten(my_list):
return list(roundrobin(*my_list))
Your original code's main issue is that it looped over for i in range(len(my_list)):, extending with my_list[i::3]. Problem is, this ends up duplicating elements from index 3 onwards (index 3 was already selected as the second element of the index 0 slice). There are lots of other small logic errors here, so it's much easier to reuse a recipe.
This will be fairly performant, and generalize better than most hand-rolled solutions (it will round robin correctly even if the sublists are of uneven length, and it doesn't require second pass filtering or special handling of any kind to allow None as a value like zip_longest does).
If you are happy to use a 3rd party library, you can use NumPy and np.ndarray.ravel:
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
res_a = A.ravel('F') # array([1, 4, 7, 2, 5, 8, 3, 6, 9])
For the case where you have one or more empty lists, you can use filter to remove empty lists:
B = np.array(list(filter(None, [[1, 2, 3], [], [7, 8, 9]])))
res_b = B.ravel('F') # array([1, 7, 2, 8, 3, 9])
Both solutions require non-empty sublists to contain the same number of items. If list conversion is necessary you can use, for example, res_a.tolist().
While these "black box" methods won't teach you much, they will be faster for large arrays than list-based operations. See also What are the advantages of NumPy over regular Python lists?
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])
This question already has answers here:
Element-wise addition of 2 lists?
(17 answers)
Closed 7 years ago.
I'm sure there is a good way to accomplish what i want without looping over lists and creating new objects. Here is what I have
a = [1, 2, 3, 4]
b = [2, 3, 4, 5]
What I am looking to do is take each set of lists and sum each placeholder so that the output is
[3, 5, 7, 9]
Thoughts?
you should use zip function and list comprehension
a = [1, 2, 3, 4]
b = [2, 3, 4, 5]
[sum(t) for t in zip(a,b)]
Use numpy
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([2, 3, 4, 5])
a+b
>>> array([3, 5, 7, 9])
This question already has answers here:
Compact way to assign values by slicing list in Python
(5 answers)
Closed 2 years ago.
Is there a fast way to get the 1st, 3rd and 5th element from an array in Python like a[0,2,4]? Thanks.
Using operator.itemgetter:
>>> lst = [1,2,3,4,5,6,7]
>>> import operator
>>> get135 = operator.itemgetter(0, 2, 4)
>>> get135(lst)
(1, 3, 5)
You could just do this, a simple method with no imports necessary:
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> [a[i] for i in (0, 2, 4)]
[1, 3, 5]
Slicing is the simplest way to do this. You'll want to slice it with [0:5:2].
>>> range(100)[0:5:2]
[0, 2, 4]
This is the equivalent of saying "Starting from element 0, up to (but not including) element 5, give me every 2nd element."
You can use slicing to get this.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
d = a[0:5:2]
print d
[1, 3, 5]
If you want to generalize to every other entry you would use
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = a[::2]
print b
[1, 3, 5, 7, 9]
You can use ,
Slicing operation on list.
>>> a=[i for i in range(10)]
>>> a[::2]
Ouput:
[0, 2, 4, 6, 8]
perhaps:
[list[0], list[2], list[4]]