I was wondering if there was a simple alternative to lambda in my code.
def add_attack(self, attack_name):
if attack_name in self.known_attacks and attack_name not in self.attacks:
try:
assert(len(self.attacks) < 4)
self.attacks[attack_name] = self.known_attacks.get(attack_name)
return True
except:
#find the min value of self.attacks
minval = min(self.attacks.keys(), key=(lambda k: self.attacks[k]))
for keys, values in self.attacks.items():
if self.attacks[minval] == values and min(minval, keys) == keys:
minval = keys
del self.attacks[minval]
self.attacks[attack_name] = self.known_attacks.get(attack_name)
return True
else:
return False
I'm still learning python, and the lambda function is throwing me off since I haven't learned that much about it yet. Instead of using lambda, can someone help me out with another function to replace lambda? Thanks!
You could define a function for it:
def return_attacks(self,k):
return self.attacks[k]
And use that function in the key:
minval = min(self.attacks.keys(), key=(self.return_attacks))
I would strongly recommend you get comfortable with lambda functions - and I think it is clear to you now that lambda x : expr(x) is equivalent to func when
def func(x):
return expr(x)
A lambda should not scare you! It's just a small anonymous function.
It can take any number of arguments, but can only have one expression.
minval = min(self.attacks.keys(), key=(lambda k: self.attacks[k]))
Here you are getting the result of the expression min() as minval
The min function can take keys, here is more about that. I can see it can be confusing, but this key is not the same thing with a dictionary key. This key is just a way to tell the min function how it should behave.
If we go back to the code:
So the line basically finds the minimum value in self.attacks.keys(), with a lambda function that returns every element in self.attacks[]
If you do not want to use lambda, you can write a function in your class that does exactly the same thing.
def find_min_key(self, my_dict):
return min(my_dict, key= my_dict.get)
You can use this as:
min_val = self.find_min_key(self.attacks)
Related
Hey I am pretty new to python and self learning it for me to eventually be somewhat decent in my coding skill i have got an idea of using map/filter/reduce functions. I am trying a challenge friend gave me to remove and element from list using remove filter and reduce
here is my code for filter
def removeall_ft(item, test_list):
res = list(filter(lambda x: x!=item, test_list))
return res
print(removeall_ft(0, [1,0,1]))
it gives [1,1]
working great
import functools
def removeall_rd(item, test_list):
res = functools.reduce(lambda x,y: x if y!=item else x, test_list)
return res
print(removeall_ft(0, [1,0,1]))
but this doesnt give me desired answer any help is appreciated
functools.reduce returns a new(or mutated) object
def reduce_step(return_so_far,this_value):
if this_value !=item:
return [*return_so_far,this_value]
return return_so_far
it takes a method to reduce, a target list, and an optional initial_value for the result (return_so_far)
item = 4
result = reduce(reduce_step,[1,2,3,4,5,6,7],[])
print(result)
as mentioned in the comments this is not a very good way to filter a list
I have a dict
x={1:1,2:2,3:8,4:8,5:2,6:7,7:4,8:9,10:2}
I want to define a function f(i) that returns the key having the value i.
Now that multiple keys have the same values, the min key should be returned.
Ex-
i=2
then in x, 2,5 and 10 has value i=2
So 2 must be returned.
i=8
3 and 4 have value 8 then 3 must be returned.
Is it possible to do this without using loops, as this function act as a base function and will be called from other function multiple times ( approx up to 10^18 )? I want to write this function without a loop. Is it possible?
Make use of min and dict comprehnesion
def find(i):
return min({k:v for k,v in x.items() if v == i}.keys())
print(find(2))
output
2
The easiest would be
def f(dictionary, target_value):
return min(filter(lambda k: dictionary[k] == target_value, dictionary.keys()))
One way to do it without directly using loops, is to use the filter() function along with the min():
x={1:1,2:2,3:8,4:8,5:2,6:7,7:4,8:9,10:2}
def f(i):
global x
return min(filter(lambda k: x[k] == i, x))
NOTE: Although I use global to be able to use x inside f(), it is better to add one more argument in f() to avoid globals:
def f(x, i):
return min(filter(lambda k: x[k] == i, x))
Testing it with the examples you provided in your question:
print(f(2))
print(f(8))
will return:
2
3
This would definitely work fine in your case try the below solution
def findMinIndexElement(to_find):
values = list(x.values())
keys = list(x.keys())
try:
return keys[values.index(to_find)]
except:
return 'Not Found'
x={1:1,2:2,3:8,4:8,5:2,6:7,7:4,8:9,10:2, 11:7}
to_find = int(input())
print(findMinIndexElement(to_find))
I recently received an answer from the stackoverflow fellow on my previous question and I tried to inquire more in order to understand the function but somehow no response so I wish to ask it here.
I wanted to know what is the k and v that used in the lambda represent? I thought it was representing like this......
k = dictionary ?
v = string ? # Did I understand it correctly?
dictionary = {"test":"1", "card":"2"}
string = "There istest at the cardboards"
from functools import reduce
res = reduce(lambda k, v: k.replace(v, dictionary[v]), dictionary, string)
since we use lambda then it loop each of the element within both of these variables. But why k.replace? Isnt that a dictionary? Should It be v.replace? Somehow this method works. I wish someone could explain to me how this work and please more details if possible. Thank you!
reduce is equivalent to repeatedly calling a function.
The function in this case is a lambda, but a lambda is just an anonymous function:
def f(k, v):
return k.replace(v, dictionary[v])
The definition of reduce itself is (almost—the None default here is not quite right, nor the len test):
def reduce(func, seq, initial=None):
if initial is not None:
ret = initial
for i in seq:
ret = func(ret, i)
return ret
# initial not supplied, so sequence must be non-empty
if len(seq) == 0:
raise TypeError("reduce() of empty sequence with no initial value")
first = True
for i in seq:
if first:
ret = i
first = False
else:
ret = func(ret, i)
return ret
So, ask yourself what this would do when called on your lambda function. The:
for i in dictionary
loop will iterate over each key in the dictionary. It will pass that key, along with the stored ret (or the initial argument for the first call), to your function. So you'll get each key, plus the string value that's initially "There istest at the cardboards", as your v (key from dictionary, called i in the expansion of reduce) and k (long string, called ret in the expansion of reduce) arguments.
Note that k is the full text string, not the string used as the key in the dictionary, while v is the word that is the key in the dictionary. I've used the variable names k and v here only because you did too. As noted in a comment, text and word might be better variable names in either the expanded def f(...) or the original lambda function.
Trace your code execution
Try the same code, except that instead of just:
def f(k, v):
return k.replace(v, dictionary[v])
you write it as:
def f(text, word):
print("f(text={!r}, word={!r})".format(text, word))
replacement = dictionary[word]
print(" I will now replace {!r} with {!r}".format(word, replacement))
result = text.replace(word, replacement)
print(" I got: {!r}".format(result))
return result
Run the functools.reduce function over function f with dictionary and string as the other two arguments and observe the output.
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)
I am supposed to write the sorting function. Define
a function sort list that takes in a list and returns a list sorted in ascending order.
(4 marks)
Note: your code should make use of the insert list function defined earlier.
With my previous defined variables:
def search(x , seq):
for i in seq:
if x > max(seq):
return len(seq)
elif x < min(seq):
return 0
return search(x, seq[:-1])
def insert_tup(x, tup):
searchtuple = search(x, tup)
ontheleft = tup[:searchtuple]
ontheright = tup[ searchtuple:]
altogether = ontheleft + (x,) + ontheright
return altogether
def insert_list(x, lst):
A = search(x, lst)
lst.insert(A, x)
return lst
I did a trial
def sort_list(lst):
result = []
for i in lst:
result += [i]
return insert_list(result[0], lst)
But i keep getting Runtime error where
File "", line 7, in search
return search(x, seq[:-1])
The output is desired to be
sort_list([5, 1, 9])
[1, 5, 9]
You are recursively calling the search() method and never breaking out of this loop. I expect this is raising a RuntimeError: maximum recursion depth exceeded exception.
Python has a recursion limit to protect against infinite recursion. FYI you can modify the recursion limit via sys.setrecursionlimit - but this is not something you should be doing.
Instead you can fix this by re-writing your algorithm iteratively.
I also suggest you read the Python sorting wiki, as this demonstrates the pythonic way to sort things with the built in sorted() function and the list method sort(). You don't need to re-invent the wheel.
You need a base case for the recursion. Something like:
if len(seq)==1:
return seq
Otherwise it calls itself forever. And the result is the error that you see.