Recursion help - Peter Norvig's Sudoku exercise - python

Hi I am currently going through Peter Norvig's sudoku solution (http://norvig.com/sudoku.html).
However, I have a bit of confusion with the block code below:
def assign(values, s, d):
"""Eliminate all the other values (except d) from values[s] and propagate.
Return values, except return False if a contradiction is detected."""
other_values = values[s].replace(d, '')
if all(eliminate(values, s, d2) for d2 in other_values):
return values
else:
return False
def eliminate(values, s, d):
"""Eliminate d from values[s]; propagate when values or places <= 2.
Return values, except return False if a contradiction is detected."""
if d not in values[s]:
return values ## Already eliminated
values[s] = values[s].replace(d,'')
## (1) If a square s is reduced to one value d2, then eliminate d2 from the peers.
if len(values[s]) == 0:
return False ## Contradiction: removed last value
elif len(values[s]) == 1:
d2 = values[s]
if not all(eliminate(values, s2, d2) for s2 in peers[s]):
return False
## (2) If a unit u is reduced to only one place for a value d, then put it there.
for u in units[s]:
dplaces = [s for s in u if d in values[s]]
if len(dplaces) == 0:
return False ## Contradiction: no place for this value
elif len(dplaces) == 1:
# d can only be in one place in unit; assign it there
if not assign(values, dplaces[0], d):
return False
return values
The function assign receive an input of a dictionary values and will return values as well if there is no contradiction. However, in the assign function, I did not see any update on the dictionary values. My understanding is that dict values is updated with the eliminate function (and after running the code, I believe this is the case). However, this is done outside of the assign function and should not affect the values in the assign function, as it is not updated directly in the function.
Maybe you guys can give me a shed of light?

Python dicts are mutable, meaning that their value can be changed.
This example is showing an anti-pattern: You shouldn't both mutate an argument and return it. An example is all the methods that change a list (append, pop, etc.) don't return the original list.
The eliminate function gets the same dict as in the assign function, and any changes in the assign function are reflected in the elimate function.
Here is an example:
def update(dict_, key, value):
dict_[key] = value
d = {
1: 2,
3: 4
}
update(d, 1, 100)
update(d, 3, 100)
print(d[1] + d[3]) # 200

Related

Find most elegant way to return key if condition is set to true

I have a python dictionary
slot_a = 'a'
slot_b = 'b'
# dict which lists all possible conditions
con_dict = {"branch_1": slot_a == 'a' and slot_b == 'b',
"branch_2": slot_a == 'a' and slot_b == 'c'}
Now I want to return the key for the first true condition. In this case it's branch_1.
My solution is:
# Pick only the condition which is set to True
true_branch = [k for k, v in con_dict.items() if v == True]
true_branch
>>> branch_1
Since the number of branches can be very long, I was wondering, if there might be a more elegant way to get the same result?! Maybe if / elif / else and then return key? Or even something completely different? All I need at the end is the name of the true condition. Therefore working with a dict may not even be necessary.
Just asking for inspiration!
You could try to use an iterator. It will stop as soon it gets the first match without going through the whole "object".
ks, vs = zip(*con_dict.items()) # decoupling the list of pairs
i = 0
vs = iter(vs) # terms are all booleans
while not next(vs):
i += 1
del vs # "free" the iterator
print(ks[i])
or
true_branch = next((k for k, condition in con_dict.items() if condition), None)
print(true_branch)

Can we return one dataframe and one variable from a function in python? [duplicate]

I would like to return two values from a function in two separate variables.
For example:
def select_choice():
loop = 1
row = 0
while loop == 1:
print('''Choose from the following options?:
1. Row 1
2. Row 2
3. Row 3''')
row = int(input("Which row would you like to move the card from?: "))
if row == 1:
i = 2
card = list_a[-1]
elif row == 2:
i = 1
card = list_b[-1]
elif row == 3:
i = 0
card = list_c[-1]
return i
return card
And I want to be able to use these values separately. When I tried to use return i, card, it returns a tuple and this is not what I want.
You cannot return two values, but you can return a tuple or a list and unpack it after the call:
def select_choice():
...
return i, card # or [i, card]
my_i, my_card = select_choice()
On line return i, card i, card means creating a tuple. You can also use parenthesis like return (i, card), but tuples are created by comma, so parens are not mandatory. But you can use parens to make your code more readable or to split the tuple over multiple lines. The same applies to line my_i, my_card = select_choice().
If you want to return more than two values, consider using a named tuple. It will allow the caller of the function to access fields of the returned value by name, which is more readable. You can still access items of the tuple by index. For example in Schema.loads method Marshmallow framework returns a UnmarshalResult which is a namedtuple. So you can do:
data, errors = MySchema.loads(request.json())
if errors:
...
or
result = MySchema.loads(request.json())
if result.errors:
...
else:
# use `result.data`
In other cases you may return a dict from your function:
def select_choice():
...
return {'i': i, 'card': card, 'other_field': other_field, ...}
But you might want consider to return an instance of a utility class (or a Pydantic/dataclass model instance), which wraps your data:
class ChoiceData():
def __init__(self, i, card, other_field, ...):
# you can put here some validation logic
self.i = i
self.card = card
self.other_field = other_field
...
def select_choice():
...
return ChoiceData(i, card, other_field, ...)
choice_data = select_choice()
print(choice_data.i, choice_data.card)
I would like to return two values from a function in two separate variables.
What would you expect it to look like on the calling end? You can't write a = select_choice(); b = select_choice() because that would call the function twice.
Values aren't returned "in variables"; that's not how Python works. A function returns values (objects). A variable is just a name for a value in a given context. When you call a function and assign the return value somewhere, what you're doing is giving the received value a name in the calling context. The function doesn't put the value "into a variable" for you, the assignment does (never mind that the variable isn't "storage" for the value, but again, just a name).
When i tried to to use return i, card, it returns a tuple and this is not what i want.
Actually, it's exactly what you want. All you have to do is take the tuple apart again.
And i want to be able to use these values separately.
So just grab the values out of the tuple.
The easiest way to do this is by unpacking:
a, b = select_choice()
I think you what you want is a tuple. If you use return (i, card), you can get these two results by:
i, card = select_choice()
def test():
....
return r1, r2, r3, ....
>> ret_val = test()
>> print ret_val
(r1, r2, r3, ....)
now you can do everything you like with your tuple.
def test():
r1 = 1
r2 = 2
r3 = 3
return r1, r2, r3
x,y,z = test()
print x
print y
print z
> test.py
1
2
3
And this is an alternative.If you are returning as list then it is simple to get the values.
def select_choice():
...
return [i, card]
values = select_choice()
print values[0]
print values[1]
you can try this
class select_choice():
return x, y
a, b = test()
You can return more than one value using list also. Check the code below
def newFn(): #your function
result = [] #defining blank list which is to be return
r1 = 'return1' #first value
r2 = 'return2' #second value
result.append(r1) #adding first value in list
result.append(r2) #adding second value in list
return result #returning your list
ret_val1 = newFn()[1] #you can get any desired result from it
print ret_val1 #print/manipulate your your result

Function would not return value, instead it returns "None"

Please help me look at this piece of code which was supposed to calculate the greatest common division between two numbers (a, b). The problem I'm having is that the program would not return c as expected, instead it return None. But when I use a print statement, it prints out the value of c.
This is my code:
def gcd(a, b):
if a == 0:
return b
elif b == 0:
return a
elif a > b:
big, small = a, b
else:
big, small = b, a
c = big % small
if c == 0:
print(small)
return small
gcd(small, c)
print(gcd(1071, 462))
Thanks guys.
Python implicitly returns None when no explicit return is encountered and the function body ends.
In your case if it passes through all other cases it just hits:
gcd(small, c)
return None # you haven't put that in explicitly but that's how Python processes it
So you probably just need to change the last line to:
return gcd(small, c)

For loop as an input parameter of a function in python

I am trying to understand solving Sudoku in Python from this website. I couldn't understand the "Search" Function in particular the application of "some" function in the "search".
def search(values):
"Using depth-first search and propagation, try all possible values."
if values is False:
return False ## Failed earlier
if all(len(values[s]) == 1 for s in squares):
return values ## Solved!
## Chose the unfilled square s with the fewest possibilities
n,s = min((len(values[s]), s) for s in squares if len(values[s]) > 1)
return some(search(assign(values.copy(), s, d))
for d in values[s])
def some(seq):
"Return some element of seq that is true."
for e in seq:
if e: return e
return False
values which is the input of the search is a dictionary (key: name of each square, value: string of possible values for that square). In the search we try to find one square( a square is a place holder of one number in Sudoku) which has the least number of possible values to fill. Then, the assign function is called for each of that values. the output of assign can be false or can be the new dictionary values. I am wondering what is the purpose of "some" function here?
This part:
search(assign(values.copy(), s, d))
for d in values[s]
is a generator expression that will recursively call search for each possible value that is valid for values[s]. It will give us a bunch of results - one for each d in values[s]. Each result will either be a dictionary (yay success) or False (boo, failure).
What some does is just pick the first success case in the group - otherwise return False.
A logically equivalent approach would be:
for d in values[s]:
e = search(assign(values.copy(), s, d))
if e: return e
return False

Python basics: How to check if a function returns mutiple values?

Basic stuff I know...;-P But what is the best way to check if a function returns some values?
def hillupillu():
a= None
b="lillestalle"
return a,b
if i and j in hillupillu(): #how can i check if i or j are empty? this is not doing it of course;-P
print i,j
If you meant that you can't predict the number of return values of some function, then
i, j = hillupillu()
will raise a ValueError if the function doesn't return exactly two values. You can catch that with the usual try construct:
try:
i, j = hillupillu()
except ValueError:
print("Hey, I was expecting two values!")
This follows the common Python idiom of "asking for forgiveness, not permission". If hillupillu might raise a ValueError itself, you'll want to do an explicit check:
r = hillupillu()
if len(r) != 2: # maybe check whether it's a tuple as well with isinstance(r, tuple)
print("Hey, I was expecting two values!")
i, j = r
If you meant that you want to check for None in the returned values, then check for None in (i, j) in an if-clause.
Functions in Python always return a single value. In particular they can return a tuple.
If you don't know how many values in a tuple you could check its length:
tuple_ = hillupillu()
i = tuple_[0] if tuple_ else None
j = tuple_[1] if len(tuple_) > 1 else None
After receiving the values from the function:
i, j = hillupillu()
You can check whether a value is None with the is operator:
if i is None: ...
You can also just test the value's truth value:
if i: ...
if(i == "" or j == ""):
//execute code
something like that should wordk, but if your giving it a None value you would do this
if(i == None or j == None):
//execute code
hope that helps
You can check whether the return value of the function is a tuple:
r_value = foo(False)
x, y = None, None
if type(r_value) == tuple:
x, y = r_value
else:
x = r_value
print(x, y)
This example is suited for a case where the function is known to return either exactly one tuple of length 2 (for example by doing return a, b), or one single value. It could be extended to handle other cases where the function can return tuples of other lengths.
I don't believe #Fred Foo's accepted answer is correct for a few reasons:
It will happily unpack other iterables that can be unpacked into two values, such as a list or string of lengths 2. This does not correspond to a return from a function that returned multiple values.
The thrown exception can be TypeError, not a ValueError.
The variables that store the return value are scoped to the try block, and so we can only deal with them inside that block.
It doesn't show how to handle the case where there is a single returned value.

Categories