This question already has answers here:
Flatten an irregular (arbitrarily nested) list of lists
(51 answers)
Closed 6 months ago.
Given a nested list of integers, implement an iterator to flatten it. Each
element is either an integer, or a list -- whose elements may also be integers
or other lists. For example, if the input is [[1,1],2,[1,1]], then the output
is [1, 1, 2, 1, 1]. If the input is [1,[4,[6]]], then the output is [1, 4, 6].
Would anyone be able to advise me as to where the code below went wrong?
I am just starting out with python.
def eb34(list1):
flat_list = []
for i in range(len(list1)):
if type(list[i]) == list:
flat_list += flatten(list1[i])
else:
flat_list.append(list1[i])
return flat_list
You can use recursion:
def flatten(arg):
if not isinstance(arg, list): # if not list
return [arg]
return [x for sub in arg for x in flatten(sub)] # recurse and collect
print(flatten([[1,1],2,[1,1]])) # [1, 1, 2, 1, 1]
print(flatten([1,[4,[6]]])) # [1, 4, 6]
Or to make a generator,
def flatten(arg):
if not isinstance(arg, list): # if not list
yield arg
else:
for sub in arg:
yield from flatten(sub)
print(*flatten([[1,1],2,[1,1]])) # 1 1 2 1 1
print(*flatten([1,[4,[6]]])) # 1 4 6
I don't know from where you are calling flatten() in your code. I am giving you a solution with the other information you have given.
def eb34(list1):
flat_list = []
for i in list1:
if isinstance(i, list):
for j in eb34(i):
flat_list.append(j)
else:
flat_list.append(i)
return flat_list
You can recursively flatten it:
def flatten_recursively(lst_in):
lst_out = []
for i in lst_in:
if type(i) == list:
for j in flatten_recursively(i):
lst_out.append(j)
else:
lst_out.append(i)
return lst_out
Also check out this answer, although you might have to adjust it to Python 3+: https://stackoverflow.com/a/10824420/18189622
The easiest way to make a flat list from nested lists is to use the itertools module. The itertools module has a function called chain that takes a list of lists and returns a single list.
>>> import itertools
>>> nested_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> flat_list = list(itertools.chain(*nested_lists))
>>> flat_list
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Related
This question already has an answer here:
list extend() to index, inserting list elements not only to the end
(1 answer)
Closed last month.
In python we can add lists to each other with the extend() method but it adds the second list at the end of the first list.
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1.extend(lst2)
Output:
[1, 4, 5, 2, 3]
How would I add the second list to be apart of the 1st element? Such that the result is this;
[1, 2, 3, 4, 5 ]
I've tried using lst1.insert(1, *lst2) and got an error;
TypeError: insert expected 2 arguments, got 3
For those who don't like reading comments:
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1[1:1] = lst2
print(lst1)
Output:
[1, 2, 3, 4, 5]
If your only goal is to get the list sorted correctly, then you use .extend() and .sort() afterwards.
You can solve your problem in two steps:
Insert the list into the other list
Flatten the result
Code:
from collections.abc import Iterable
# https://stackoverflow.com/questions/2158395/flatten-an-irregular-arbitrarily-nested-list-of-lists
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
xs = [1,4,5]
ys = [2,3]
xs.insert(1, ys)
print("intermediate result", xs)
xs = flatten(xs)
print(xs)
This question already has answers here:
Flatten an irregular (arbitrarily nested) list of lists
(51 answers)
Closed 4 years ago.
I have a list in Python.
I have tried to set print(*arr, sep=",") refer "Print list without brackets in a single row". But my real problem is:
### List
num = 2
arr= [0, "txt", 4, 5, [3,4, num]]
# print full
print(arr)
# print an arr without brackets
print(*arr, sep=",")
Expected result:
0,txt,4,5,3, 4, 2
Actual result:
0,txt,4,5,[3, 4, 2]
The compiler does not remove brackets from sub-list. Please give me advice to fix it. Thanks!
Use a function to flatten the list first, and then print the new list.
def flatten(original, iterables=[list]):
out = []
for val in original:
if type(val) not in iterables:
out.append(val)
else:
out += flatten(val)
return out
print(flatten(arr))
Here I explicitly specify type(val) != list so that it will not attempt to split up your strings, but will flatten sub lists. Additionally, this method will handle nested lists of any depth.
Result:
>>> print(flatten(arr))
[0, 'txt', 4, 5, 3, 4, 2]
You can also pass a second argument iterables, which is a list containing what iterable types you wish to flatten. This can include list, tuple, or anything else. Here I default to list since that's what your example requires.
try this for removing nested bracket only from the list:
num = 2
arr = [0, "txt", 4, 5, [3,4, num]]
output = []
def removeBracket(arr):
for i in arr:
if type(i) == list:
removeBracket(i)
else:
output.append(i)
removeBracket(arr)
print(output) # [0, 'txt', 4, 5, 3, 4, 2]
def only_evens(lst):
""" (list of list of int) -> list of list of int
Return a list of the lists in lst that contain only even integers.
>>> only_evens([[1, 2, 4], [4, 0, 6], [22, 4, 3], [2]])
[[4, 0, 6], [2]]
"""
even_lists = []
for sublist in lst:
for i in sublist:
if i % 2 == 0:
even_lists.append(i)
return even_lists
I can't do this because it returns everything in one list[]
But how can I return sublist that consists only with even integers?
I would split it into two functions: one which checks if a list contains only even numbers, and the other one is your main function (I renamed it to get_even_lists()), which gets all the even lists from a list of lists:
def only_even_elements(l):
""" (list of int) -> bool
Return a whether a list contains only even integers.
>>> only_even_elements([1, 2, 4]) # 1 is not even
False
"""
for e in l:
if e % 2 == 1:
return False
return True
def get_even_lists(lst):
""" (list of list of int) -> list of list of int
Return a list of the lists in lst that contain only even integers.
>>> only_evens([[1, 2, 4], [4, 0, 6], [22, 4, 3], [2]])
[[4, 0, 6], [2]]
"""
# return [l for l in lst if only_even_elements(l)]
even_lists = []
for sublist in lst:
if only_even_elements(sublist):
even_lists.append(sublist)
return even_lists
Although, this could be done with for/else:
def get_even_lists(lst):
""" (list of list of int) -> list of list of int
Return a list of the lists in lst that contain only even integers.
>>> only_evens([[1, 2, 4], [4, 0, 6], [22, 4, 3], [2]])
[[4, 0, 6], [2]]
"""
even_lists = []
for sublist in lst:
for i in sublist:
if i % 2 == 1:
break
else:
even_lists.append(sublist)
return even_lists
Or as others have suggested, a one-liner:
def get_even_lists(lst):
""" (list of list of int) -> list of list of int
Return a list of the lists in lst that contain only even integers.
>>> only_evens([[1, 2, 4], [4, 0, 6], [22, 4, 3], [2]])
[[4, 0, 6], [2]]
"""
return [sublst for sublst in lst if all(i % 2 == 0 for i in sublst)]
But let's be honest here: while it's arguable that using two functions might be a bit longer and not as "cool" as the other two solutions, it's reusable, easy to read and understand, and it's maintainable. I'd argue it's much better than any other option out there.
You could also do this using functional programming:
def only_evens(lst):
return filter(lambda ls: all(map(lambda n: not n & 1, ls)), lst)
EDIT
As per J.F. Sebastian's recommendation, I split this into three functions:
is_odd = lambda n: n & 1
all_even = lambda arr: not any(map(is_odd, arr))
only_evens = lambda arr: filter(all_even, arr)
is_odd one checks if a number is odd using bitwise operations for efficiency. all_even checks if a list has all even numbers and returns a boolean. only_evens takes a list of list of integers and returns a list of the lists that contain only even integers.
I would think not about what you are keeping, but about what you're removing (all lists containing an odd number). Something like
import copy
list_copy = copy.copy(lists)
def only_evens(list_copy):
for l in list_copy:
for i in l:
if i % 2 != 0:
list_copy.remove(l)
break
return(list_copy)
(which emphasizes readability over conciseness, to be sure.)
I guess you can divide your problem into small parts.
def contains_only_evens(lst):
return sum([x%2 for x in lst]) == 0
def only_evens(lst):
for sublist in lst:
if not contains_only_evens(sublist):
lst.remove(sublist)
return lst
In this way you can:
iterate over a list and its sublists
check if the list contains any odd integer
keep only sublist with no odds values
This question already has answers here:
Remove adjacent element in a list in python
(2 answers)
Closed 7 years ago.
I have a list like this: [1, 3, 4, 5, 1]
and I want to remove the first n elements, so for n = 3, I want to return that list, while removing it from the original list. So I'd have [1,3,4]
and my original list is now [5, 1].
What is the best way to do that in python?
In Python 2.7 this would look like the following. Simply extract a partial list and delete the unneeded part in the original version.
lst = [1, 3, 4, 5, 1]
new_lst = lst[:3]
del lst[:3]
print lst
print new_lst
If you want to mutate the original object, you can change it using [:]. For example:
>>> x = ['a','b','c','d','e']
>>> x[:], removed = x[3:], x[:3]
>>> x
['d', 'e']
>>> removed
['a', 'b', 'c']
This works because the terms on the right hand side, x[3:] and x[:3], are both evaluated before they're assigned to the targets on the left (x[:] and removed).
Something like this?
def pop_n(lst, n):
"""
Deletes the first *n* elements from *lst* and returns them.
"""
# validate inputs
# might want to use something other than isinstance()
if not isinstance(n, int) or n < 0:
raise ValueError("n must be a non-negative integer, not {}"
.format(n))
# store the elements to return
ret = lst[:n]
# remove the elements from the original list
del lst[:n]
return ret
EDIT: Here's a demonstration with your example case.
>>> x = [1, 3, 4, 5, 1]
>>> pop_n(x, 3)
[1, 3, 4]
>>> x
[5, 1]
>>> original = [1, 3, 4, 5, 1]
>>> removed, original[:3] = original[:3], ()
>>> removed, original
([1, 3, 4], [5, 1])
I want to get the number of times x appears in the nested list.
if the list is:
list = [1, 2, 1, 1, 4]
list.count(1)
>>3
This is OK. But if the list is:
list = [[1, 2, 3],[1, 1, 1]]
How can I get the number of times 1 appears? In this case, 4.
>>> L = [[1, 2, 3], [1, 1, 1]]
>>> sum(x.count(1) for x in L)
4
itertools and collections modules got just the stuff you need (flatten the nested lists with itertools.chain and count with collections.Counter
import itertools, collections
data = [[1,2,3],[1,1,1]]
counter = collections.Counter(itertools.chain(*data))
print counter[1]
Use a recursive flatten function instead of itertools.chain to flatten nested lists of arbitrarily level depth
import operator, collections
def flatten(lst):
return reduce(operator.iadd, (flatten(i) if isinstance(i, collections.Sequence) else [i] for i in lst))
reduce with operator.iadd has been used instead of sum so that the flattened is built only once and updated in-place
Here is yet another approach to flatten a nested sequence. Once the sequence is flattened it is an easy check to find count of items.
def flatten(seq, container=None):
if container is None:
container = []
for s in seq:
try:
iter(s) # check if it's iterable
except TypeError:
container.append(s)
else:
flatten(s, container)
return container
c = flatten([(1,2),(3,4),(5,[6,7,['a','b']]),['c','d',('e',['f','g','h'])]])
print(c)
print(c.count('g'))
d = flatten([[[1,(1,),((1,(1,))), [1,[1,[1,[1]]]], 1, [1, [1, (1,)]]]]])
print(d)
print(d.count(1))
The above code prints:
[1, 2, 3, 4, 5, 6, 7, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
1
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
12
Try this:
reduce(lambda x,y: x+y,list,[]).count(1)
Basically, you start with an empty list [] and add each element of the list list to it. In this case the elements are lists themselves and you get a flattened list.
PS: Just got downvoted for a similar answer in another question!
PPS: Just got downvoted for this solution as well!
If there is only one level of nesting flattening can be done with this list comprenension:
>>> L = [[1,2,3],[1,1,1]]
>>> [ item for sublist in L for item in sublist ].count(1)
4
>>>
For the heck of it: count to any arbitrary nesting depth, handling tuples, lists and arguments:
hits = lambda num, *n: ((1 if e == num else 0)
for a in n
for e in (hits(num, *a) if isinstance(a, (tuple, list)) else (a,)))
lst = [[[1,(1,),((1,(1,))), [1,[1,[1,[1]]]], 1, [1, [1, (1,)]]]]]
print sum(hits(1, lst, 1, 1, 1))
15
def nested_count(lst, x):
return lst.count(x) + sum(
nested_count(l,x) for l in lst if isinstance(l,list))
This function returns the number of occurrences, plus the recursive nested count in all contained sub-lists.
>>> data = [[1,2,3],[1,1,[1,1]]]
>>> print nested_count(data, 1)
5
The following function will flatten lists of lists of any depth(a) by adding non-lists to the resultant output list, and recursively processing lists:
def flatten(listOrItem, result = None):
if result is None: result = [] # Ensure initial result empty.
if type(listOrItem) != type([]): # Handle non-list by appending.
result.append(listOrItem)
else:
for item in listOrItem: # Recursively handle each item in a list.
flatten(item, result)
return result # Return flattened container.
mylist = flatten([[1,2],[3,'a'],[5,[6,7,[8,9]]],[10,'a',[11,[12,13,14]]]])
print(f'Flat list is {mylist}, count of "a" is {mylist.count("a")}')
print(flatten(7))
Once you have a flattened list, it's a simple matter to use count on it.
The output of that code is:
Flat list is [1, 2, 3, 'a', 5, 6, 7, 8, 9, 10, 'a', 11, 12, 13, 14], count of "a" is 2
[7]
Note the behaviour if you don't pass an actual list, it assumes you want a list regardless, one containing just the single item.
If you don't want to construct a flattened list, you can just use a similar method to get the count of any item in the list of lists, with something like:
def deepCount(listOrItem, searchFor):
if type(listOrItem) != type([]): # Non-list, one only if equal.
return 1 if listOrItem == searchFor else 0
subCount = 0 # List, recursively collect each count.
for item in listOrItem:
subCount += deepCount(item, searchFor)
return subCount
deepList = [[1,2],[3,'a'],[5,[6,7,[8,9]]],[10,'a',[11,[12,13,14]]]]
print(f'Count of "a" is {deepCount(deepList, "a")}')
print(f'Count of 13 is {deepCount(deepList, 13)}')
print(f'Count of 99 is {deepCount(deepList, 99)}')
As expected, the output of this is:
Count of "a" is 2
Count of 13 is 1
Count of 99 is 0
(a) Up to the limits imposed by Python itself of course, limits you can increase by just adding this to the top of your code:
import sys
sys.setrecursionlimit(1001) # I believe default is 1000.
I mention that just in case you have some spectacularly deeply nested structures but you shouldn't really need it. If you're nesting that deeply then you're probably doing something wrong :-)