007 spy question in python. what am i missing? - python

I am trying to solve a problem called spy game in which you need to return true if there is 0,0,7 in order but they don't need to be consecutive, and otherwise, it should return false.
For example:
spy_game([1,2,4,0,0,7,5]) should return True
spy_game([1,0,2,4,0,5,7]) should return True
spy_game([1,7,2,0,4,5,0]) should return False
here is my code:
def spy_game(nums):
for x in range(4):
if nums[x]==0:
for y in range(x+1,len(nums)):
if nums[y]==0:
for z in range(y+1,len(nums)):
if nums[z]==7:
return True
What I am lacking is though the return is false if the given condition is false. I couldn't find an appropriate place to put a return false because otherwise, it affects the solution. My solution seems to be right for returning true. How can I solve this? Thanks in advance.

you can delete all numbers that you don't want and search '007', like:
myList = [1,2,4,0,0,7,5]
myList = [str(x) for x in l if x==0 or x==7 ] #just 0 or 7
strOfMyList = ''.join(myList)
print(strOfMyList.find('007')>=0)
#find return -1 if doesn't find else the first occurrence
In a function it looks like:
def spy_game(nums):
nums = [str(x) for x in nums if x==0 or x==7 ]
strOfMyList = ''.join(nums)
return strOfMyList.find('007')>=0

Related

Loop over list with and condition

I am trying to write a code for below pseudocode
for all element in list do
match and condition
if all match
return True
for example, List A=[1,2,3,4,5],B=10
What I want is like
def match():
for i in range(len(A)):
if B%A[0]==0 and B%A[1]==0 and B%A[2]==0 and B%A[3]==0 and B%A[4]==0: #Generate all these
#and condition one by one
#automatically in this function
return True
How can I do?
NOTE:I am asking about write code match and condition with a loop, not write a remainder
Try this one:
result = all( [(B%a==0) for a in A] )
You can use a pythonic one liner
result = all(B % x == 0 for x in A)
Or maybe in a slightly more familiar syntax
res = True
for x in A:
if B % x != 0:
res = False
break

Is there any way to write with less "nesting"?

The problem is a homework problem. I think I solved it but I'm wondering is it the best solution? The problem is to take a list and run through it to see if it contains a specific subsequence: 007. Here subsequence is used in the mathematical sense (so 0110227 does contain 007 and returns True).
def spy_game(nums):
if 0 in nums:
a_1=nums.index(0)
nums_1=nums[a_1+1:]
if 0 in nums_1:
a_2=nums_1.index(0)
if 7 in nums[a_2+1:]:
return True
else:
return False
else:
return False
else:
return False
Start by negating your test condition so you can simply return early. The last test doesn't require an if statement at all, since by that point the result of the condition is the return value of the function.
def spy_game(nums):
if 0 not in nums:
return False
a_1 = nums.index(0)
nums_1 = nums[a_1+1:]
if 0 not in nums_1:
return False
a_2 = nums_1.index(0)
return 7 in nums[a_2+1:]
If you negate your inclusion conditions you can return early rather than introducing further nesting.
def spy_game(nums):
if 0 not in nums:
return False
a_1 = nums.index(0)
num_1 = nums[a_1+1:]
if 0 not in nums_1:
return False
a_2 = nums_1.index(0)
return 7 in nums_1[a_2+1:]
You can also write this without creating any copies of the list by using the start parameter to the index method, which will tell the index method the index at which to start searching for the element. This code looks different but achieves the same thing and may be easier to maintain for you.
def spy_game(nums):
try:
start = 0
for n in [0, 0, 7]:
start = nums.index(n, start)
return True
except ValueError:
return False
It's better to design your functions so that they don't depend on the specific input. For example:
def contains_anywhere(s, search):
i = 0
for c in search:
try:
i = s.index(c, i) + 1
except ValueError:
return False
return True
ok = contains_anywhere([0,1,1,0,2,2,7,2], [0,0,7])
Just another option, I personally don't see an issue with the nesting here.
This is shortening it up:
def spy_game(nums):
if 0 in nums:
nums_1 = nums[nums.index(0)+1:]
if 0 in nums_1:
if 7 in nums[nums_1.index(0)+1:]:
return True
return False
output:
>>> spy_game([1,0,7])
False
>>> spy_game([0,1,7])
False
>>> spy_game([1,0,1])
False
>>> spy_game([0,0,7])
True
Your code hides what you are trying to do. Try this alternative. even though it still has 3 levels of nesting, it is clearer about what it is doing:
def spy_game(nums):
search_for = [x for x in "007"]
for n in nums:
if not search_for: # found everything we were looking for
return True
if n == search_for[0]: # found the next item
search_for.pop(0)
return False

Why am I getting a syntax error (python number checking function)?

I've written this function in Python, which is designed to check if any list element is a number, and return that list element if it is. This is the code:
def check_for_number(list):
x = 0
print(isinstance(list[x], (int, float))
true_or_false = False
for x in range(len(list)-1):
if isinstance(list[x], (int, float) == True):
true_or_false = True
num = list[x]
x += 1
print(true_or_false)
return true_or_false
return num
Whenever I try to run it I get a syntax error saying that the colon at the end of the if statement is an 'unexpected token', and every item in the last two lines of the if statement gives the same unexpected token error. I've checked the indentation and I can't see anything wrong with it, what am I missing? Thanks.
You just have to indend the code of your function and fix the if isinstance(list[x], (int, float) == True): part and close the paranthesis of your first print statement.
def check_for_number(list):
x = 0
print(isinstance(list[x], (int, float)))
true_or_false = False
for x in range(len(list)-1):
if isinstance(list[x], (int, float)) == True:
true_or_false = True
num = list[x]
x += 1
print(true_or_false)
# Decide what you want to return here
return true_or_false
return num
If you are interested in improving your code, remove the == True part, as has been stated in the comments as well. And from your question I assume you want to return fals, if true_or_false is False or num otherwise.
If you add a breakstatement in the loop, the loop will be exited when you have found the first number. So your computer does not need to loop through the complete list and this can save you some execution time.
I also expect, your x += 1 statement is not what you want to do. The for ... in range ... loop will increase your x in each cycle. That is why x += 1 will make your code skip every second list element. You also will not need to declare x first.
def check_for_number(list):
print(isinstance(list[x], (int, float)))
true_or_false = False
for x in range(len(list)-1):
if isinstance(list[x], (int, float)):
true_or_false = True
num = list[x]
break
print(true_or_false)
if (true_or_false):
return num
else:
return False
Concering your question about the unnecessary == True part:
The if statement is working like the following pseudo code.
if (CONDITION) == True then do something special
So, if you add a == True, python would check it like so:
if (valeu == True) == True then do something special
which is the same as:
if (value) == True then do something special
Here is a solution using a list comprehension. It checks each element against the Number abstract base class. It will return a list of numbers, since there might be more than 1 numeric elelement.
import numbers
def get_numbers(l):
return [x for x in l if isinstance(x, numbers.Number)]
example:
>>> l = ['1', 4.0, 'abc', 'XYZ', 'test', 5]
>>> nums = get_numbers(l)
>>> print(nums)
[4.0, 5]
Python is tab-sensitive and intolerant of errors in this regard. I'm also seeing an instance of an unmatched parenthesis on line 6. Try the following and you might get a more informative error on what to fix next:
def check_for_number(list):
x = 0
print(isinstance(list[x], (int, float))
true_or_false = False
for x in range(len(list)-1):
if isinstance(list[x], (int, float) == True): # missing a parenthesis to close isinstance.
# "== True" is unnecessary because isinstance() will resolve to True or False
true_or_false = True
num = list[x]
x += 1
print(true_or_false)
return true_or_false
return num # this will result in unexpected behavior...
# ...because num will not be defined if this line is reached.
# Either the return inside the if will finish the method or num will never be defined.
It's a bit ambiguous how some of that should be indented because I can't tell what you're trying to do.
If you're trying to return to values, consider returning a list or a dictionary containing the values.

Python, check if sets check out

I have made the function, but I need to make a guess so it will run through the function and check if it fits, if not, start over again with new numbers.
If I find a set that works, the loop should break, the problem is that I am new to python and math programming.
def checkStuff(X):
ok = True
#i.
if(min(X) <= 0):
ok = False
#ii.A
A = set()
for x in X:
A.add(x % 2)
#ii.B
B = set()
for y in X:
B.add(y**2)
#ii.C
C = set()
for z in X & B:
C.add(z**0.5)
#ii.D
D = set()
for w in C:
D.add(w**2)
#iii.
if(len(X)<=0):
ok = False
#iv.
if(len(X) not in X):
ok = False
#v.
if len(A) in X:
ok = False
#vi.
if sum(X) not in B:
ok = False
#vii.
if sum(X&B) in B:
ok = False
#viii.
if sum(C.union(D)) not in X:
ok = False
return ok
without giving you the exact code, try looking at the while loop and the random function
Your function can be simplified and optimized, returning as soon as possible, avoiding further computations... for compactness I used set comprehensions instead of your loops
def checkStuff(X):
if(min(X) <= 0): return False
if(len(X)<=0): return False
if(len(X) not in X): return False
A = {x % 2 for x in X}
if len(A) in X: return False
B = {x**2 for x in X}
if sum(X) not in B: return False
if sum(X&B) in B: return False
C = {xb**0.5 for xb in X&B}
D = {c**2 for c in C}
if sum(C.union(D)) not in X: return False
return True
Assuming that you have a function that returns a list of trial sets or, possibly better, yields a new trial set for each loop, and that you want to use ONLY the first X that matches your conditions, then you can write your stuff like this
for X in generate_trial_sets():
if checkStuff(X):
do_stuff(X)
break
else:
print("No X was generated matching the criteria")
...
Note that the else clause is aligned correctly, because Python has a for ... else .. control flow construct.
Blind Attempt at a generate_trial_sets Function
Given that each X is a set of numbers (integers? reals? complex numbers? who knows? you, but you didn't care to tell...) and that we don't know how many numbers you want in the set, and also that you want to stop the iteration somehow, I'd write
def generate_trial_sets(nmin=1, nmax=5,
xmin=0.0, xmax=10.0, iterations=10):
from random import randint
for _ in range(iterations):
n = randint(nmin,nmax+1)
x = {n}
for i in range(1,n):
x.add((xmax-xmin)*random()+xmin)
yield x
When you call it like
for X in generate_trial_sets():
without modifying the default args, you get back 10 sets of length comprised between 1 and 5, with real values comprised between 0 and 10 (one of the values is equal to the length, so one of your tests is automatically fulfilled).
To use different parameters, specify them at the invocation:
for X in generate_trial_sets(nmin=6,nmax=6,xmax=100.0,iterations=200):
This is not a solution of your problem but if you understand the logic you'll get started in the right direction or, at least, I hope so...

How can I return false if more than one number while ignoring "0"'s?

This is a function in a greater a program that solves a sudoku puzzle. At this point, I would like the function to return false if there is more then 1 occurrence of a number unless the number is zero. What do am I missing to achieve this?
L is a list of numbers
l =[1,0,0,2,3,0,0,8,0]
def alldifferent1D(l):
for i in range(len(l)):
if l.count(l[i])>1 and l[i] != 0: #does this do it?
return False
return True
Assuming the list is length 9, you can ignore the inefficiency of using count here (Using a helper datastructure - Counter etc probably takes longer than running .count() a few times). You can write the expression to say they are all different more naturally as:
def alldifferent1D(L):
return all(L.count(x) <= 1 for x in L if x != 0)
This also saves calling count() for all the 0's
>>> from collections import counter
>>> def all_different(xs):
... return len(set(Counter(filter(None, xs)).values()) - set([1])) == 0
Tests:
>>> all_different([])
True
>>> all_different([0,0,0])
True
>>> all_different([0,0,1,2,3])
True
>>> all_different([1])
True
>>> all_different([1,2])
True
>>> all_different([0,2,0,1,2,3])
False
>>> all_different([2,2])
False
>>> all_different([1,2,3,2,2,3])
False
So we can break this down into two problems:
Getting rid of the zeros, since we don't care about them.
Checking if there are any duplicate numbers.
Striping the zeros is easy enough:
filter(lambda a: a != 0, x)
And we can check for differences in a set (which has only one of each element) and a list
if len(x) == len(set(x)):
return True
return False
Making these into functions we have:
def remove_zeros(x):
return filter(lambda a: a != 0, x)
def duplicates(x):
if len(x) == len(set(x)):
return True
return False
def alldifferent1D(x):
return duplicates(remove_zeros(x))
One way to avoid searching for every entry in every position is to:
flags = (len(l)+1)*[False];
for cell in l:
if cell>0:
if flags[cell]:
return False
flags[cell] = True
return True
The flags list has a True at index k if the value k has been seen before in the list.
I'm sure you could speed this up with list comprehension and an all() or any() test, but this worked well enough for me.
PS: The first intro didn't survive my edit, but this is from a Sudoku solver I wrote years ago. (Python 2.4 or 2.5 iirc)

Categories