Using functions on lists - python

I have a function that determines if the number is less than 0 or if there isn't a number at all
def numberfunction(s) :
if s == "":
return 0
if s < 0 :
return -1
if s > 0:
return s
i also have a list of lists
numbers = [[]]
now, lets say i filled the list of lists with numbers like:
[[1,2,3,4],[1,1,1,1],[2,2,2,2] ..etc ]
how would i go about calling up the function i had above into the numbers i have in the lists?
Would I require a loop where I use the function on every number of every list, or is it simpler than that?

You can use map and a list comprehension to apply your function to all of your elements. Please note that I have modified your example list to show all of the return cases.
def numberfunction(s) :
if s == "":
return 0
if s < 0 :
return -1
if s > 0:
return s
# Define some example input data.
a = [[1,2,3,""],[-1,1,-1,1],[0,-2,-2,2]]
# Apply your function to each element.
b = [map(numberfunction, i) for i in a]
print(b)
# [[1, 2, 3, 0], [-1, 1, -1, 1], [None, -1, -1, 2]]
Note that, with the way your numberfunction works at the moment, it will return None for an element equal to zero (thanks to #thefourtheye for pointing this out).

You can also call nested map():
>>> a = [[1,2,3,""],[-1,1,-1,1],[2,-2,-2,2]]
>>> map(lambda i: map(numberfunction, i), a)
[[1, 2, 3, 0], [-1, 1, -1, 1], [2, -1, -1, 2]]
>>>
I have Python < 3 in which map returns list.

You could do it as:
result = [[numberfunction(item) for item in row] for row in numbers]

Related

Returning the First Number of a List

So, I'm trying to create a script where the first even number of a determined list is returned. If the list contains no even numbers it returns -1.
At first I was trying to use str.find(), but I just don't know how to make it work.
Any help?
from typing import List
def f_even(items: List[int]) -> int:
"""
>>>f_even([1, 3, 4, 6])
4
>>>f_even([1, 3])
-1
"""
even_numbers = []
even = even_numbers[0]
for number in items:
if number % 2 == 0:
even_numbers.append(number)
return even
Right now I get an error where even = even_numbers[0]; the index is out of range. I feel like I'm complicating this code a lot.
Use next() on a generator and return -1 for no-even case.
lst = [1, 3, 4, 6]
print(next((x for x in lst if x % 2 == 0), -1))
# 4
On special case (no evens):
lst = [1, 3, 3, 9]
print(next((x for x in lst if x % 2 == 0), -1))
# -1
You could use a if/else block before you attempt to call even[0], if your even has values then you can call even[0] else return/print -1
even = []
for number in items:
if not number % 2:
even.append(number)
if even:
print(even[0])
else:
print(-1)
That's because right after you create even_numbers, the list is empty, and even = even_numbers[0] tries to get the first element of it, which is not there.
You can assign -1 to even, and then update it in the loop. If there's no even number in the loop, it will still be -1, so the method would return -1.
a = [1,2,3,4]
b = [1,3,5,7]
def even(x):
for a in x:
if a%2==0:
f = 0
break
else:
f = -1
return f
print(a,even(a))
print(b,even(b))
OP:
([1, 2, 3, 4], 0)
([1, 3, 5, 7], -1)

How to return the index of the first non-negative list in a list of lists in Python?

The desired output is the index of the first non-negative list.
Say I nested list of numbers like below. I am trying to figure out how to remove the values of the negative lists or just return the index where all the values in the list are positive.
My idea was to enumerate or loop a function that checks if a list has a negative value then pop or remove from the list of lists
Or do I use a list comprehension?
# pseudocode
x = [[-1, -2, -1], [-1, -3, -1], [1, 2, 2]]
index_x = [x.index(non_negative(x)) for x in data]
print(index_x)
# 2
You can use next with a generator expression and enumerate + all. Your logic is equivalent to finding the index of the first sublist containing all non-negative values.
x = [[-1, -2, -1], [-1, -3, -1], [1, 2, 2]]
res = next((idx for idx, sub in enumerate(x) if all(i >= 0 for i in sub)), None)
# 2
A list comprehension is only useful if you wish to extract indices for all sublists matching a condition. The built-in next function retrieves the first value from an iterable. If no sublist is found, the specified None will be returned.
For this I'd just use a function with an early return, which I feel makes the intent of "stop looking when you find this" clearer:
def first_non_negative(lsts):
for idx, lst in enumerate(lsts):
if all(it > 0 for it in lst):
return idx
Why not do something like this? Just iterate through the lists.
from functools import reduce
x = [[-1, -2, -1], [-1, -3, -1], [1, 2, 2]]
for index, sublist in enumerate(x):
if reduce(lambda a, b: a >= 0 and b >= 0, sublist):
print(index)
break

Python generator with external break condition

I need to iterate over ascending sequences x of n (= 5, f.i.) integers, finding all sequences for which a function f(*x) returns True.
Assume that if f_n(*y) is False for a particular y, then f_n(*z) id False for any z with z_i >= y_i. So f_n is monotonic in all its arguments.
This kind of generator function could be used in the following way to determine all ascending sequences of integers that have a sum of squares < 100
for sequence in generate_sequences(5):
if sum_squares_is_at_least(sequence, 100):
# some code to trigger the breaking of the generator loop
else:
print sequence
Clarification:
The problem here is that we need to iterate of n elements individually. Initially, we iterate [1,1,1,1,1] to [1,1,1,1,x], and then we have to continue with [1,1,1,2,2] to [1,1,1,2,y], eventually ending with [a,b,c,d,e]. It seems that the generator should look something like this, but needs some code to break out of the for and/or while loops if necessary (determined externally):
def generate_sequences(length, minimum = 1):
if length == []:
yield []
else:
element = minimum
while True:
for sequence in generate_sequences(length - 1, element):
yield element + [sequence]
element += 1
Example:
For n = 3, and sum of squares no larger than 20, the following sequences would be generated:
[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4], [1, 2, 2], [1, 2, 3], [1, 3, 3], [2, 2, 2], [2, 2, 3]
Note that in the general case, I cannot use the information that 4 is the upper bound for each element. This would also seriously impact the running time for larger examples.
Are you looking for itertools.takewhile?
>>> from itertools import takewhile
>>> def gen(): #infinite generator
... i=0
... while True:
... yield range(i,i+5)
... i = i+1
...
>>> [ x for x in takewhile( lambda x:sum(x)<20, gen() ) ]
[[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]
>>>
import itertools as it
it.takewhile(lambda x: sum_squares_is_at_least(x, 100), generate_sequences(5))
If you are now sure about the 5 in the generate_sequences, then just let it yield the numbers as long as it is called:
def generate_sequences():
i = 0 # or anything
while True:
yield [i, i] # or anything
i = i + 1 # or anything
Then use it this way:
it.takewhile(lambda x: sum_squares_is_at_least(x, 100), generate_sequences())
I would solve it with recursion by starting with a given list then appending another number (with logic to prevent going over sum of squares target)
def makegen(N): #make a generator with max sumSquares: N
def gen(l=[]): #empty list is valid with sum == 0
yield l
if l:
i = l[-1] #keep it sorted to only include combinations not permutations
else:
i = 1 #only first iteration
sumsquare = sum(x*x for x in l) #find out how much more we can add
while sumsquare + i*i < N: #increase the appended number until we exceed target
for x in gen(l+[i]): #recurse with appended list
yield x
i += 1
return gen
calling our generator generator (tee hee :D) in the following fashion allows us to have any maximum sum of squares we desire
for x in makegen(26)():
print x

Apply Indicator Function to List

Is there an easy way to apply an indicator function to a list? i.e. I have a list with some numbers in it and I would like to return another list of the same size with, for example, ones where the positive numbers were in the original list and zeros where the negative numbers were in the original list.
Just use a list comprehension:
>>> orig = [-3, 2, 5, -6, 8, -2]
>>> indic = [1 if x>0 else 0 for x in orig]
>>> indic
[0, 1, 1, 0, 1, 0]
List comprehensions!
bysign = [int(x >= 0) for x in somelist]
Here's a demo.
To produce the results of your example, I probably would have done
cmp_list=map(cmp, your_list)
one_zero_list=[]
for item in cmp_list:
if item < 0:
one_zero_list.append(0)
elif item==0:
one_zero_list.append(0) #you didnt actually say what to do with 0
else:
one_zero_list.append(1)

return a list containing elements of another list

I need to write an expression and I'm completely stuck. I have part of the code that I think I have written correctly but I'm stick on the rest of it. I need the code to return a new list containing every 3rd element in the list, starting at index 0.
For example: if I have the list [0, 1, 2, 3, 4, 5] I need it to return [0, 3]
The code I have so far is:
result = []
i = 0
while i < len(L):
result.append(L[i])
i =
return result
Can someone please help me figure out what I need the i = expression to be for this code to work.
First of all, you can make use of extended slice notation to make things easier:
In [1]: l = [0, 1, 2, 3, 4, 5]
In [2]: l[::3]
Out[2]: [0, 3]
From the docs:
Some sequences also support “extended slicing” with a third “step” parameter: a[i:j:k] selects all items of a with index x where x = i + n*k, n >= 0 and i <= x < j.
As for your code sample, you probably need i = i + 3 or i += 3 there.
Maybe try this:
result = []
for i in range(0, len(L), 3):
result.append(L[i])
return result
Another alternative is to use enumerate.
[j for i, j in enumerate([0, 1, 2, 3, 4, 5]) if i % 3 == 0]
this will give tyou an iterable sequence:
import itertools
l = [0, 1, 2, 3, 4, 5]
itertools.islice(l, 0, None, 3)
to turn it into a list, use the list() function.
impiort itertools
def get_sublist(l):
return list(itertools.islice(l, 0, None, 3))
python 3.2
one way:
>>> [i for i in range(0,len(L),3)]
[0,3]
your method:
result = []
i = 0
while i <= len(L):
result.append(L[i])
i+=3
return result

Categories