How can I use a function call result in a conditional list comprehension? - python-3.x

I would like to turn this code into a list comprehension:
l = list()
for i in range(10):
j = fun(i)
if j:
l.append(j)
Meaning that I'd like to add only truthy fun() result values to the list. Without the truthy check of that function call, the list comprehension would be:
l = [fun(i) for i in range(10)]
Adding a if fun(i) to the list comprehension would cause two evaluations of fun() per iteration (actually, not always it seems!), thus causing unintended side effects if fun() is not pure.
Can I capture the result of fun(i) and use it in that same comprehension, essentially adding the if j? (Related question here)

You can make an inner generator in the list comp so you will look over the results of func
l = [j for j in (func(i) for i in range(10)) if j]

Or combining two suggested solutions:
filter(None, (func(i) for i in range(10)))

Edit
Much simpler:
[res for res in map(func, range(10)) if res]
Thanks for the hint to falstru.
Old answer
Another option would to use a helper generator function:
def call_iter(func, iterable):
for arg in iterable:
yield func(arg)
[res for res in call_iter(func, range(10)) if res]

Related

Issues with list comprehensions

My goal was to create a method that would take an array as parameter, and output the sum of the min() value of each of its subarrays. However, I really don’t understand what’s wrong with my list comprehension.
class Solution(object):
def sumSubarrayMins(self, arr):
s = 0
self.subarrays = [arr[i:j] for i in range(j-1,len(arr))for j in range(1,len(arr)+1)]
for subarray in self.subarrays:
s += min(subarray)
return s
sol = Solution()
sol.sumSubarrayMins([3,1,2,4])
I often try debugging with python tutor but it is really no help in this case.
Your subarray calculation logic is wrong. You are trying to use j in the first loop, before you define it. Try this:
self.subarrays = [arr[i:j] for i in range(0, len(arr)) for j in range(i+1, len(arr)+1)]

Math-like way to define a set in Python: technical name [duplicate]

Can someone explain the last line of this Python code snippet to me?
Cell is just another class. I don't understand how the for loop is being used to store Cell objects into the Column object.
class Column(object):
def __init__(self, region, srcPos, pos):
self.region = region
self.cells = [Cell(self, i) for i in xrange(region.cellsPerCol)] #Please explain this line.
The line of code you are asking about is using list comprehension to create a list and assign the data collected in this list to self.cells. It is equivalent to
self.cells = []
for i in xrange(region.cellsPerCol):
self.cells.append(Cell(self, i))
Explanation:
To best explain how this works, a few simple examples might be instructive in helping you understand the code you have. If you are going to continue working with Python code, you will come across list comprehension again, and you may want to use it yourself.
Note, in the example below, both code segments are equivalent in that they create a list of values stored in list myList.
For instance:
myList = []
for i in range(10):
myList.append(i)
is equivalent to
myList = [i for i in range(10)]
List comprehensions can be more complex too, so for instance if you had some condition that determined if values should go into a list you could also express this with list comprehension.
This example only collects even numbered values in the list:
myList = []
for i in range(10):
if i%2 == 0: # could be written as "if not i%2" more tersely
myList.append(i)
and the equivalent list comprehension:
myList = [i for i in range(10) if i%2 == 0]
Two final notes:
You can have "nested" list comrehensions, but they quickly become hard to comprehend :)
List comprehension will run faster than the equivalent for-loop, and therefore is often a favorite with regular Python programmers who are concerned about efficiency.
Ok, one last example showing that you can also apply functions to the items you are iterating over in the list. This uses float() to convert a list of strings to float values:
data = ['3', '7.4', '8.2']
new_data = [float(n) for n in data]
gives:
new_data
[3.0, 7.4, 8.2]
It is the same as if you did this:
def __init__(self, region, srcPos, pos):
self.region = region
self.cells = []
for i in xrange(region.cellsPerCol):
self.cells.append(Cell(self, i))
This is called a list comprehension.

comparing elements of a list from an *args

I have this function that I need to compare the strings in a list to a *args
The reason being is that, the user should be able to type any words in the 2nd argument. However when I try to compare the strings to the *args it doesn't give me any results
def title_case2(title, *minor_words):
for x in title.split():
if x in minor_words:
print(x)
Assuming I ran the function with the parameters below. I was hoping it would display a and of since these words are found on those 2 entries.
title_case2('a clash of KINGS','a an the of')
*args is a tuple of arguments, so you're actually checking if x is in ('a an the of',). So either pass your argument as:
title_case2('a clash of KINGS', *'a an the of'.split())
Or, use this as your test:
if any(x in y for y in minor_words):
In either of the above cases the output is:
a
of
This is one approach.
Ex:
def title_case2(title, *minor_words):
minor_words = [j for i in minor_words for j in i.split()] #Create a flat list.
for x in title.split():
if x in minor_words:
print(x)
title_case2('a clash of KINGS','a an the of', "Jam")
using a for-loop instead of list comprehension
def title_case2(title, *minor_words):
minor_words_r = []
for i in minor_words:
for j in i.split():
minor_words_r.append(j)
for x in title.split():
if x in minor_words_r:
print(x)

using recursion to eliminate duplicates

i'm just starting to learn how recursion works and i keep getting stuck on what i think should be a simple question. I need to create a function using recursion that takes a list and returns a new list with only 1 of each value within the original list.
Example:
original_list = [1,1,2,3,3,4,5]
returned_list = [1,2,3,4,5]
what i have tried:
def recursion(list1):
new_list = []
if list1 == []:
new_list = []
else:
if list1[0] not in list1[1:]:
new_list = new_list.append(list1[0]) + recursion (list1[1:])
else:
new_list = recursion (list1[1:])
return new_list
You're not passing new_list as a parameter to the recursive function; therefore, each level of the recursion is unaware of the results you have gathered so far, and the result of the recursion is only the result of the first level.
(I'm refraining from posting the corrected code since you would presumably like to fix it yourself, and thereby learn more - let me know if you need more hints.)

k way merge sort divide and conquer

from math import ceil
def merge(all_lst):
sorted_lst = []
while all_lst:
min_value,index = all_lst[0][0],0
for lst in all_lst:
if lst[0]<min_value:
min_value = lst[0]
index = all_lst.index(lst)
sorted_lst.append(min_value)
all_lst[index].pop(0)
if not all_lst[index]:
all_lst.remove(all_lst[index])
return sorted_lst
def merge_sort(lst, k):
def split(lst):
split_lst = []
j = ceil(len(lst)/k) if len(lst)>=k else 1
for i in range(0,len(lst),j):
split_lst.append(lst[i:i+j])
return split_lst
lst=split(lst)
if len(lst[0])==1:
return lst
else:
for i in range(len(lst)):
lst[i]=merge(merge_sort(lst[i],k))
return merge(lst)
Above is my code for k-way merge sort. Basically what it does is split the list into k smaller list by calling the split function until each sublist in the list is a single element. Then the list containing sublists will be merged into one single list.
My code works fine when splitting is done twice. (eg.[3,6,8,5,2,1,4,7] -> [3,6,8],[5,2,1],[4,7] -> [3],[6],[8],[5],[2],[1],[4],[7]). But when the splitting is done more than twice, (eg,[3,6,8,5,2,1,4,7] -> [3,6,8,5],[2,1,4,7] -> [3,6],[8,5],[2,1],[4,7] -> [3],[6],[8],[5],[2],[1],[4],[7]), the code will fail. Can anyone help find me find out what goes wrong in my code? Thanks in advance.
I believe the problem you're having is that merge_sort sometimes returns a flattened list and other times returns a list of lists. You should probably return a flat list in all cases. There's some other cruft: You don't need split to be its own function, since you only call it the one time.
Here's a greatly simplified version of your code:
def merge_sort(lst, k):
if len(lst) == 1: # simpler base case
return lst
j = ceil(len(lst)/k) # no need to check for k < len(lst) (ceil handles it)
#split and recursively sort in one step
lst = [merge_sort(lst[i:i+j], k) for i in range(0, len(lst), j)]
return merge(lst) # always return a merged list (never a list of lists)

Resources