Why does the second print lookup method return a blank and not the link acm.org? The first result makes sense but shouldn't the second result be similar?
# Define a procedure, lookup,
# that takes two inputs:
# - an index
# - keyword
# The procedure should return a list
# of the urls associated
# with the keyword. If the keyword
# is not in the index, the procedure
# should return an empty list.
index = [['udacity', ['http://udacity.com', 'http://npr.org']],
['computing', ['http://acm.org']]]
def lookup(index,keyword):
for p in index:
if p[0] == keyword:
return p[1]
return []
print lookup(index,'udacity')
#>>> ['http://udacity.com','http://npr.org']
print lookup(index,'computing')
Results:
['http://udacity.com', 'http://npr.org']
[]
Your indentation has a typo. You are returning [] if the first entry doesn't match. It should be:
def lookup(index,keyword):
for p in index:
if p[0] == keyword:
return p[1]
return []
I highly recommend use dictionaries for this case.
It will be like that:
index = {'udacity': ['http://udacity.com', 'http://npr.org'],
'computing': ['http://acm.org']}
def lookup(index, keyword):
return index[keyword] if keyword in index else []
This is faster and clearly. And for sure, you have more possibilities for flexible work with dict than with [list of [lists of 'strings' and [list of 'strings']]].
Related
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
For example
def find_all_occurrences(a,b):
'''
>>>find_all_occurrences('wswwswwwswwwws', ['ws', 'wws'])
[[0,3,7,12], [2,6,11]]
'''
How can I return a list of lists that have all the occurrences without import any modules.
You can use regular expressions
import re
def all_occurrences(a, b):
return [[occur.start() for occur in re.finditer(word, a)] for word in b]
Without imports it gets a little messy, but definitely still doable
def all_occurrences(a, b):
result = []
for word in b:
word_res = []
index = a.find(word)
while index != -1:
word_res.append(index)
index = a.find(word, index+1)
result.append(word_res)
return result
You can find all the occurrences by using the last found position as the start of the next search:
str.find(...)
S.find(sub [,start [,end]]) -> int
Return the lowest index in S where substring sub is found,
such that sub is contained within S[start:end]. Optional
arguments start and end are interpreted as in slice notation.
Return -1 on failure.
A loop that calls haystack.find(needle, last_pos + 1) repeatedly until it returns -1 should work.
you can also have simple list comprehensions to help with problems like these
[[i for i in range(len(a)-len(strng)+1) if strng == a[i:i+len(strng)]] for strng in b]
where
>>> a
'wswwswwwswwwws'
>>> b
['ws', 'wws']
Solution with a recursive procedure. I used a nested/inner function to maintain the OP's function signature:
def find_all_occurrences(a,b):
'''
>>>find_all_occurrences('wswwswwwswwwws', ['ws', 'wws'])
[[0,3,7,12], [2,6,11]]
'''
def r(a, b, count = 0, result = None):
if not a:
return result
if result is None:
# one sublist for each item in b
result = [[] for _ in b]
for i, thing in enumerate(b):
if a.startswith(thing):
result[i].append(count)
return r(a[1:], b, count = count + 1, result = result)
return r(a, b)
I'm attempting to generate all n choose k combinations of a list (not checking for uniqueness) recursively by following the strategy of either include or not include an element for each recursive call. I can definitely print out the combinations but I for the life of me cannot figure out how to return the correct list in Python. Here are some attempts below:
class getCombinationsClass:
def __init__(self,array,k):
#initialize empty array
self.new_array = []
for i in xrange(k):
self.new_array.append(0)
self.final = []
self.combinationUtil(array,0,self.new_array,0,k)
def combinationUtil(self,array,array_index,current_combo, current_combo_index,k):
if current_combo_index == k:
self.final.append(current_combo)
return
if array_index >= len(array):
return
current_combo[current_combo_index] = array[array_index]
#if current item included
self.combinationUtil(array,array_index+1,current_combo,current_combo_index+1,k)
#if current item not included
self.combinationUtil(array,array_index+1,current_combo,current_combo_index,k)
In the above example I tried to append the result to an external list which didn't seem to work. I also tried implementing this by recursively constructing a list which is finally returned:
def getCombinations(array,k):
#initialize empty array
new_array = []
for i in xrange(k):
new_array.append(0)
return getCombinationsUtil(array,0,new_array,0,k)
def getCombinationsUtil(array,array_index,current_combo, current_combo_index,k):
if current_combo_index == k:
return [current_combo]
if array_index >= len(array):
return []
current_combo[current_combo_index] = array[array_index]
#if current item included & not included
return getCombinationsUtil(array,array_index+1,current_combo,current_combo_index+1,k) + getCombinationsUtil(array,array_index+1,current_combo,current_combo_index,k)
When I tested this out for the list [1,2,3] and k = 2, for both implementations, I kept getting back the result [[3,3],[3,3],[3,3]]. However, if I actually print out the 'current_combo' variable within the inner (current_combo_index == k) if statement, the correct combinations print out. What gives? I am misunderstanding something to do with variable scope or Python lists?
The second method goes wrong because the line
return [current_combo]
returns a reference to current_combo. At the end of the program, all the combinations returned are references to the same current_combo.
You can fix this by making a copy of the current_combo by changing the line to:
return [current_combo[:]]
The first method fails for the same reason, you need to change:
self.final.append(current_combo)
to
self.final.append(current_combo[:])
Check this out: itertools.combinations. You can take a look at the implementation as well.
I am making a String Rewriting Function that takes a string and rewrites it according to the rules in a dictionary. The code works perfectly fine once but I need it to call itself n times and print the 'nth' rewritten string. The code that works that I need to be recursive is:
S = "AB"
def srs_print(S, n, rules):
'''
A function that takes a dictionary as SRS rules and prints
the output
'''
axiom = list(S)
key = []
value = []
output = ''
for k in rules:
#Inputs the keys of the rules dictionary into a new list
key.append(k)
#Inputs the value of the rules dictionary into a new list
value.append(rules[k])
for x in axiom:
if x in key:
axiomindex = key.index(x)
output += value[axiomindex]
else:
output += x
S = output
return S
#j = srs_print(S, 5, {'A':'AB', 'B': 'A'})
#print(j)
#while len(range(n)) > 0:
# S = srs_print(S, n, rules)
# n = n-1
#print("The", n, "th rewrite is " )
#j = srs_print(S, 5, {'A':'AB', 'B': 'A'})
print(srs_print("A", 5, {'A':'AB', 'B': 'A'}))
This turns "A" into "AB" but I need it to put 'S' back into the function and run again 'n'times. As you can see, some of the commented code are lines I have tried to use but have failed.
I hope I've explained myself well enough.
If I understand correctly, you pass "n" to the function as a way to count how many times you need to call it.
You could probably get away with enclosing the whole body of the function in a for or a whileloop.
If you want it to be recursive anyway, here's how it could work:
You need to have "two" return statements for your function. One that returns the result (in your case, "S"), and another one, that returns srs_print(S, n-1, rules)
Ex:
if n > 0:
return srs_print(S, n-1, rules)
else:
return S
I suggest you take some time and read this, to get a better understanding of what you want to do and whether or not it is what you should do.
You definitly don't need recursion here. First let's rewrite your function in a more pythonic way:
def srs_transform(string, rules):
'''
A function that takes a dictionary as SRS rules and prints
the output
'''
# the short way:
# return "".join(rules.get(letter, letter) for letter in string)
# the long way
output = []
for letter in string:
transformed = rules.get(letter, letter)
output.append(transformed)
return "".join(output)
Now we add a wrapper function that will take care of applying srs_transform a given number of times to it's arguments:
def srs_multi_transform(string, rules, times):
output = string
for x in range(times):
output = srs_transform(output, rules)
return output
And now we just have to call it:
print(srs_transform("A", {'A':'AB', 'B': 'A'}, 5))
>> ABAABABAABAAB
Why not simply use a for-loop?
def srs_print(S, n, rules):
for _ in range(n):
S = ''.join(rules.get(x, x) for x in S)
return S
my code consists of me recreating the function 'filter()' and using it with a function to filter words longer than 5 characters. It worked with the actual function filter when I tried it btw...I'm using python 3+
def filter1(fn, a):
i = 0
while i != len(a):
u = i - 1
a[i] = fn(a[i], a[u])
i += 1
return a
def filter_long_words(l):
if len[l] > 5:
return [l]
listered = ['blue', 'hdfdhsf', 'dsfjbdsf', 'jole']
print(list(filter1(filter_long_words, listered)))
getting error
TypeError: filter_long_words() takes 1 positional argument but 2 were given
You are passing two parameters to fn (which refers to filter_long_words) here:
a[i] = fn(a[i], a[u])
But filter_long_words only accepts one parameter.
Notes:
You can loop through lists using for item in my_list, or if you want index as well for index, item in enumerate(my_list).
I think you might get an IndexError since u will be -1 in the first round of your loop.
The filter function can also be expressed as a list comprehension: (item for item in listered if filter_long_words(item))
My version of filter would look like this, if I have to use a for loop:
def my_filter(fn, sequence):
if fn is None:
fn = lambda x: x
for item in sequence:
if fn(item):
yield item
Since you have stated that you are using Python 3, this returns a generator instead of a list. If you want it to return a list:
def my_filter(fn, sequence):
if fn is None:
fn = lambda x: x
acc = []
for item in sequence:
if fn(item):
acc.append(item)
return acc
If you don't need to use a for loop:
def my_filter(fn, sequence):
if fn is None:
fn = lambda x: x
return (item for item in sequence if fn(item))
Your're calling fn with 2 parameters in filter1(fn, a), and since you've passed filter_long_words() to filter1 as fn, that triggers the error.
But there's more weird stuff:
I don't understand the magick of filter1 or what you were trying to
accomplish, but it seems to me that you don't have a clear idea what to do.
But if you want to mimic (somehow) how filter works, you have to return a
list which contains only items for which the fn function returns true. When
you know this, you can rewrite it - here are a few suggestions for rewrite
# explicit, inefficient and long, but straightforward version:
def filter1(fn, a):
new_list = []
for item in a:
if fn(item):
new_list.append(item):
return new_list
# shorter version using list comprehensions:
def filter1(fn, a):
return [item for item in a if fn(item)]
The filter_long_words function is wrong too - it should return True or
False. The only reason why it could work is because any non-empty list is
treated as True by python and default return value of a function is None,
which translates to False. But it's confusing and syntactically wrong to use
len[l] - the proper usage is len(l).
There are a few suggestions for rewrite, which all returns explicit boolean
values:
# unnecessary long, but self-explanatory:
def filter_long_words(l):
if len(l) > 5:
return True
else
return False
# short variant
def filter_long_words(l):
return len(l) > 5
You are calling "filter_long_words" with 2 parameter => fn(a[i], a[u]) also there is an error
def filter_long_words(l):
if **len[l]** > 5:
return [l]
len is builtin method it should be len(l)