iterating through a list with an if statement - python

I have a list that I am looping through with a "for" loop and am running each value in the list through an if statement. My problem is that I am trying to only have the program do something if all the values in the list pass the if statement and if one doesn't pass, I want it to move along to the next value in the list. Currently it is returning a value if a single item in the list passes the if statement. Any ideas to get me pointed in the right direction?

Python gives you loads of options to deal with such a situation. If you have example code we could narrow that down for you.
One option you could look at is the all operator:
>>> all([1,2,3,4])
True
>>> all([1,2,3,False])
False
You could also check for the length of the filtered list:
>>> input = [1,2,3,4]
>>> tested = [i for i in input if i > 2]
>>> len(tested) == len(input)
False
If you are using a for construct you can exit the loop early if you come across negative test:
>>> def test(input):
... for i in input:
... if not i > 2:
... return False
... do_something_with_i(i)
... return True
The test function above will return False on the first value that's 2 or lower, for example, while it'll return True only if all values were larger than 2.

Maybe you could try with an for ... else statement.
for item in my_list:
if not my_condition(item):
break # one item didn't complete the condition, get out of this loop
else:
# here we are if all items respect the condition
do_the_stuff(my_list)

You need to loop through your whole list and check the condition before trying to do anything else with the data, so you need two loops (or use some built in that does the loop for you, like all()). From this codepad with nothing too fancy, http://codepad.org/pKfT4Gdc
def my_condition(v):
return v % 2 == 0
def do_if_pass(l):
list_okay = True
for v in l:
if not my_condition(v):
list_okay = False
if list_okay:
print 'everything in list is okay, including',
for v in l:
print v,
print
else:
print 'not okay'
do_if_pass([1,2,3])
do_if_pass([2,4,6])

You must always be careful if you're deleting items from your list while you're trying to iterate through it.
If you're not deleting then does this help:
>>> yourlist=list("abcdefg")
>>> value_position_pairs=zip(yourlist,range(len(yourlist)))
>>> value_position_pairs
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6)]
>>> filterfunc=lambda x:x[0] in "adg"
>>> value_position_pairs=filter(filterfunc,value_position_pairs)
>>> value_position_pairs
[('a', 0), ('d', 3), ('g', 6)]
>>> yourlist[6]
'g'
now if value_position_pairs is empty you're done. If not you can increase i by one to go to the next value or iterate through the failed values using their position in the array.

Related

What does this Python 3 function do?

Can anybody help me to find out how this function works?
def get_matched_birthdays(birthdays):
if len(birthdays) == len(set(birthdays)):
return None
for a, birthdayA in enumerate(birthdays):
for b, birthdayB in enumerate(birthdays[a+1:]):
if birthdayA == birthdayB:
return birthdayA
Here is birthdays: https://ghostbin.com/paste/4tM0V
I am understanding the first two lines but what's happening inside those two for loops?
The function basically loops through the "birthdays" list and checks to see if an element appears further down the list and returns the value every time it sees it down the line.
First for loop just loops through the "birthdays" list and gives each element an index which is stored in variable "a".
for a, birthdayA in enumerate(birthdays):
The second loop takes a subset of "birthdays" list and loops through it. The subset starts at the index "a+1" and ends at the end of the "birthdays" list.
for b, birthdayB in enumerate(birthdays[a+1:]):
The function then returns the values where the items in "birthdays" list comes up again in the list.
if birthdayA == birthdayB:
return birthdayA
If you want a more efficient way of checking for dupes and returning the index of dupes perhaps use something like this:
>>> dupes_lst = []
>>> unique_set = set()
>>> lst = [1,2,3,1,1,4,2]
>>> for i, item in enumerate(lst):
... if item in unique_set:
... dupes_lst.append(i)
... else:
... unique_set.add(item)
More on enumerate at https://docs.python.org/3/library/functions.html :
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

Cyclist to list of functions, and combine their results until a match is found

I have multiple lists of functions, that are called using lambdas:
a = [ lambda: func_a1(a11, a12, a13), lambda: func_a2(a21, a23) ...]
b = [ lambda: func_b1(b11, b12), lambda: func_b2(b21) ...]
A function can return a result or triggers an exception:
def func_a1(a11, a12, a13):
...do something
return result
raise CustomException
Later in code I'm cycling thru the function. If the function triggers an error, I skip and continue to next function, if not I return. If no return an exception is raised
def cycle1():
for f in a :
try:
return f()
except CustomException:
continue
raise CustomException
Similar def cycle2 for b list etc.
Then the results from cycle1 and cycle2 are combined and compare with a source of truth.
For simplification, something like:
a,b = cycle1(), cycle2()
if a + b == c:
do something
The solution has flaws, because if didn't match doesn't return to try other combinations. If a and b not equal with c I want to get the next value, but I'm already out of function. For example:
if a[0] and b[0] returns but not equal c, then test a[1][b0]
if a[0] trigger exception combine a[1] with b[0]. If not equal c, combine a[1] and b[1]
There are the combinations of the functions returns(that didn't triggered an error).Also I want to favour a cycling first before b(a loops, b states on first element, and the loop move b to second elements).
Even scale to have more lists, like a, b, c as list. I'm thinking maybe to use generators to cycle.
I need an ideea, python or pseudo code, to implement it, to avoid the issues of my initial solution
if I understand correctly, you want to try out all combination of your functions, if so, that can be done with itertools.product, for example
>>> import itertools
>>> list(itertools.product([1,2,3],"a b c".split()))
[(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (3, 'a'), (3, 'b'), (3, 'c')]
>>>
For your particular use, you can do the following, but with some changes to your cycle functions that I will show later
for a, b in itertools.product(cycle1(), cycle2()):
if a+b==c:
#do something
the change necessary to work like this, is to transform it into a generator, with is a simple change of return to yield
def cycle1():
for f in a :
try:
yield f()
except CustomException:
continue
#raise CustomException
as a generator it will cycle through all the function on your list a, and not just stop on the first success as with is the case for return; tho maybe leave out the last exception, if you get to the end of the product combination you will know that you didn't find what you where searching for
here is sample generator
>>> def gen(nums):
for n in nums:
yield 10+n
>>> list(gen([1,2,3]))
[11, 12, 13]
>>>
Another change that can be made is, if cycle2 is identical to cycle1 except for the list, then don't repeat yourself and make cycle take that list as argument, and the exception too now that we are at it
def cycle(fun_list,exc=CustomException):
for f in fun_list :
try:
yield f()
except exc:
continue
with that the previous is now
for a, b in itertools.product(cycle(list_a), cycle(list_b)):
if a+b==c:
#do something

printing out tuples from function

Im making this function that prints the index number with the item from the string but I need it to print out as tuples, for example
[(0, 'dog'), (1, 'pig'), (2, 'cow')]
how would I go about doing this? it just prints each out on one line so far.
this is my code so far.
def my_enumerate(items):
"""return a list of tuples where item is the i'th item """
for item in items:
index = items.index(item)
print(item, index)
my_enumerate(['dog', 'pig', 'cow'])
thank you
def my_enumerate(items):
"""return a list of tuples where item is the i'th item """
l = []
for index in range(len(items)):
t = (index, items[index])
l.append(t)
return l
res = my_enumerate(['x', 'x', 'x'])
print(res)
I would suggest:
def my_enumerate(items):
print([(i, animal) for i, animal in enumerate(items)])
the reason you are printing them one by one is that you are printing them one by one inside the loop, to get all of them at once you will need to create a list and print that at the end of the loop. there are several ways to go about this and m0nte-cr1st0 gave you the most legible one, ill give you something a little shorter:
def my_enumerate(items):
return list(zip(range(len(items)), items))
zip lets you smoosh together 2 lists pairwise
this solution of course assumes you cant just use the built in enumerate
In expression
print(list(enumerate(items)))
part enumerate(['dog', 'pig', 'cow']) will create an iterator over the list of tuples [(0, 'dog'), (1, 'pig'), (2, 'cow')] you want to print , so you can just create a list with this iterator and print it.

For x in string , how to check if x is last

Is there a way to know if x is the last element of a string in the following basic example of a for loop
for x in string_time:
do something
If you want to know whether x is physically the last element in the string, you can use enumerate():
for i,x in enumerate(string_time, start=1-len(string_time)):
if not i:
# last element
...
If, on the other hand, you want to know whether x is equal to the last element, you can simply use == (as was also mentioned in the comments):
for x in string_time:
if x == string_time[-1]:
# last element
...
Just to describe what's going on in the first snippet: we're enumerating the string starting at 1-len(string), which does the following:
>>> s = 'abc'
>>>
>>> list(enumerate(s, start=1-len(s)))
[(-2, 'a'), (-1, 'b'), (0, 'c')]
So the last element is enumerated with 0, meaning we can use the not i check to check if we're on the last element.
Another option is to process the last character in the string separately from the loop
for x in string_time[:-1]:
# do stuff
last_char = string_time[-1]
This assumes that the string is non-empty.

Generate combinations of elements from multiple lists

I'm making a function that takes a variable number of lists as input (i.e., an arbitrary argument list).
I need to compare each element from each list to each element of all other lists, but I couldn't find any way to approach this.
Depending on your goal, you can make use of some of the itertools utilities. For example, you can use itertools.product on *args:
from itertools import product
for comb in product(*args):
if len(set(comb)) < len(comb):
# there are equal values....
But currently it's not very clear from your question what you want to achieve. If I didn't understand you correctly, you can try to state the question in a more specific way.
I think #LevLeitsky's answer is the best way to do a loop over the items from your variable number of lists. However, if purpose the loop is just to find common elements between pairs of items from the lists, I'd do it a bit differently.
Here's an approach that finds the common elements between each pair of lists:
import itertools
def func(*args):
sets = [set(l) for l in args]
for a, b in itertools.combinations(sets, 2):
common = a & b # set intersection
# do stuff with the set of common elements...
I'm not sure what you need to do with the common elements, so I'll leave it there.
The itertools module provides a lot of useful tools just for such tasks. You can adapt the following example to your task by integrating it into your specific comparison logic.
Note that the following assumes a commutative function. That is, about half of the tuples are omitted for reasons of symmetry.
Example:
import itertools
def generate_pairs(*args):
# assuming function is commutative
for i, l in enumerate(args, 1):
for x, y in itertools.product(l, itertools.chain(*args[i:])):
yield (x, y)
# you can use lists instead of strings as well
for x, y in generate_pairs("ab", "cd", "ef"):
print (x, y)
# e.g., apply your comparison logic
print any(x == y for x, y in generate_pairs("ab", "cd", "ef"))
print all(x != y for x, y in generate_pairs("ab", "cd", "ef"))
Output:
$ python test.py
('a', 'c')
('a', 'd')
('a', 'e')
('a', 'f')
('b', 'c')
('b', 'd')
('b', 'e')
('b', 'f')
('c', 'e')
('c', 'f')
('d', 'e')
('d', 'f')
False
True
if you want the arguments as dictionary
def kw(**kwargs):
for key, value in kwargs.items():
print key, value
if you want all the arguments as list:
def arg(*args):
for item in args:
print item
you can use both
def using_both(*args, **kwargs) :
kw(kwargs)
arg(args)
call it like that:
using_both([1,2,3,4,5],a=32,b=55)

Categories

Resources