How to get only even numbers from list - python

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

Related

finding all the indices of with a value in a list of lists

I am trying to find all the indices that have the same values in a list.
but in my list, there are lists inside the list and I don't know how to do it
I found how to do that for a normal list:
list=[2,5,9,1,3,1]
list.index(1)
it will print the indices of value
1: [3,5]
but for this list:
list=[1, [2,3,17] , 3 , [0,1,2,7,3] , 2 ]
for the value 2
it will need to print: [[1, 0], [3, 2], [4]]
but I don't know how to do that for this kind of list.
Firstly, don't name any variables list in python -- it is already a function.
To answer the question, you can loop through the list and use recursion each time there is a list inside of the list:
def getNestedIdxs(l, num): # l is the list and num is what we are looking for
result = []
for idx, element in enumerate(l):
if element == num: result.append([idx])
elif isinstance(element, list): # This checks if the element is a list
result.extend([[idx] + elem for elem in getNestedIdxs(element, num)])
return result
print(getNestedIdxs([[[1, 2, 3,[0,1,2]], 2, [1, 3]], [1, 2, 3]], 2))

How to make a flat list from nested lists? [duplicate]

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]

Making a multidimensional list flat where the sublists are equal to their average

So for example, I have the list = [1, [2, [3, [5, [5]]]]] the resulting list would be [1,3].
I currently have this,
def avg(mylist):
if mylist == []:
return mylist
elif type(mylist[0]) == list:
mylist[0] = 0 # average of mylist[0]
return mylist[:1]+avg(mylist[1:])
elif type(mylist[0]) == float:
return mylist[:1]+avg(mylist[1:])
Which works the way I want it too but I cannot find a way to set mylist[0] = the average of mylist[0]. I have also tried it a lot of different ways but I cannot find one that works.
EDIT: Another example of something I tried.
total = 0
nosublist=True
if mylist == []:
return mylist
for x in mylist:
if type(x) == list:
nosublist=False
if nosublist:
return mylist[:1]+average(mylist[1:])
elif not nosublist:
for x in mylist:
if type(x) == list:
total += average(x)
else:
total += x
mylist[0] = total/len(mylist)
return average(mylist[:1])+average(mylist[1:])
def isiter(x):
try:
iter(x)
return True
except TypeError:
return False
def _flatten(x, reduce=iter):
for i in x:
if isiter(i):
r = reduce((j for j in _flatten(i, reduce=reduce)))
if isiter(r):
yield from r
else:
yield r
else:
yield i
Now you can plugin mean
def mean(x):
l = list(x)
return sum(l)/len(l)
l = [1, [2, [3, [5, [5]]]]]
list(_flatten(l, reduce=mean))
>>> [1, 3.0]
or
mean(flatten(l, reduce=mean))
>>> 2.0
EDIT:
If you really need only a single function:
def flatten(x, reduce=iter):
return reduce(_flatten(x, reduce=reduce))
This isn't probably the best solution but you could use it help make yours even better! I created two lists on each recursive call one with only elements that aren't lists and one with elements that were all lists (just in case you had a format like [1, 3, [2], [2], [3, [5, [5, 5]]]]) and created a call stack to take the sum of the elements in each inner array and one to take the length of each inner array and then took the average. Of course since there might be multiple arrays in the list of arrays you can map this same functionality for each array and accumulate their avg's.
code
list1 = [1, [2, [3, [5, [5]]]]]
list2 = [1, [2, 3], [4, 5], [5, [3, 4]]]
def avg(mylist):
"""flattens an array where the sublists to flatten are the average of that sublist"""
subarrays = filter(lambda x: type(x) == type([]), mylist)
rootelems = filter(lambda x: type(x) != type([]), mylist)
avg_all = lambda elem: sum((avg(elem))) / len(avg(elem))
if subarrays == []:
return mylist
return rootelems + map(avg_all, subarrays)
print avg(list1)
print avg(list2)
result
[1, 3]
[1, 2, 4, 4]

Recursively find the kth largest int in list of list of int in Python

As a newbie in programming, I am trying to do a function to find the kth largest int in a list of list of ints. I tried list of ints before and it worked.
However, for this function, its base case has too many possibilities:
Ex: [1, 2], [[], 1], [[1], 2], [[1], [1]]
I got stuck at the base case. Can anyone give me a hint for this?
This function would operate like:
find_2smallest([1,1,3])->1
find_2smallest([[1,[]], 9, [[1], [3]], [4]])->3
some hints:
write a flatten function to convert list hierarchy to a single collection (with unique elements), sort and pick the k'th element.
sample implementation
def flatten(t):
for e in t:
if isinstance(e,list):
yield from flatten(e)
else:
yield e
set(flatten([[1,[]], 9, [[1], [3]], [4]]))
{1, 3, 4, 9}
of course, this approach is not the most efficient (perhaps it's the least efficient). You can return the first k elements from each sub level and prune at k'th level at each merge.
I wrote a generalized solution (you specify k) using extra arguments with default values to track both the smallest set of k found so far, and whether this was the top level of the recursion or a sub-level. Sub-levels return the current smallest subset, the top level returns the last entry (which is the kth smallest value). The smallest set of k is maintained using heapq's nsmallest method.
import heapq
def find_kth_smallest(k, a_list, smallest_k = [], top_level = True):
l = len(a_list)
if l > 1:
l /= 2
smallest_k = find_kth_smallest(k, a_list[:l], smallest_k, False)
smallest_k = find_kth_smallest(k, a_list[l:], smallest_k, False)
elif l < 1:
return []
else:
if isinstance(a_list[0], list):
smallest_k = find_kth_smallest(k, a_list[0], smallest_k, False)
else:
smallest_k.append(a_list[0])
smallest_k = heapq.nsmallest(k, smallest_k)
if top_level:
return smallest_k[-1]
else:
return smallest_k
print find_kth_smallest(3, [10, [9, 8, [[]]], [7, 6, [[5], 4, 3]], 2, 1]) # => 3

How to print data from list of list with recursion

Python. It is given list of list. How to make function which will data from list represent like 'moreline' string' like that every data will be shown in its new line, and in front of it are so many '*' as many as depth of data is.
Example : we have list [2, 4, [[3, 8], 1]] and now function has to make and return string, which function 'print' prints it out like this:
* 2
* 4
*** 3
*** 8
** 1
I have made for now just this and its not working
def Function(List):
s=''
Count=0
for element in List:
Count+=1
if type(element)==type([]):
s+=Function(element)
else:
s+=Count*'*'+str(element)+('\n')
return s
if a replace return (s) with print(s) it report me an error ... but if i return s and than myself print that string it works normally , but once again not how it should
>>> Function([2, 4, [[3, 8], 1]])
'*2\n*4\n*3\n*8\n**1\n'
>>> print('*2\n*4\n*3\n*8\n**1\n')
*2
*4
*3
*8
**1
Where is the problem, I can't find it. What should I replace, remove, etc.?
def r(l, depth=0, ret=[]):
if isinstance(l,list):
for i in l:
r(i, depth+1)
else:
ret.append('*' * depth + str(l))
return ret
print '\n'.join(r([2, 4, [[3, 8], 1]]))
output:
*2
*4
***3
***8
**1
You need to pass on count to recursive calls; local variables do not magically transfer to new function invocations:
def format_nested(lst, depth=1):
s = []
for element in lst:
if isinstance(element, list):
s.append(print_nested(element, depth + 1))
else:
s.append('{0} {1}\n'.format(depth * '*', element))
return ''.join(s)
I addressed various other issues with the code:
Use descriptive function and argument names. Function is not a great name.
Use a list to build up elements of a string, then use str.join(); it is faster than building up strings by concatenation.
Only increment the depth counter when recursing, not for every element in current level of the list.
Use isinstance() to test for specific types.
String formatting makes it a little easier to build strings together with constant elements, such as a space and a newline.
Demo:
>>> format_nested([2, 4, [[3, 8], 1]])
'* 2\n* 4\n*** 3\n*** 8\n** 1\n'
>>> print format_nested([2, 4, [[3, 8], 1]])
* 2
* 4
*** 3
*** 8
** 1
Often it's easier to express these things as a generator
L = [2, 4, [[3, 8], 1]]
def nest_gen(L):
if isinstance(L, list):
for i in L:
for j in nest_gen(i):
yield "*"+str(j)
else:
yield L
for row in nest_gen(L):
print(row)
In Python3.3+ you can use yield from
L = [2, 4, [[3, 8], 1]]
def nest_gen(L):
if isinstance(L, list):
yield from ("*"+str(j) for i in L for j in nest_gen(i))
else:
yield L
for row in nest_gen(L):
print(row)
Instead of catenating strings over and over, you can yield the depth/item as a tuple
L = [2, 4, [[3, 8], 1]]
def nest_gen(L):
if isinstance(L, list):
yield from ((j+1, k) for i in L for j, k in nest_gen(i))
else:
yield 0, L
for item in nest_gen(L):
print("{:*>{}} {}".format('', *item))

Categories