I have very little experience in coding and I'm learning Python in a class. I'm learning about conditionals and loops and have been asked to create a function that'll take an arbitrary amount of arguments and give me the maximum. Obviously I'm not allowed to use the built-in max function.
So far, I have:
def max(x):
current_max = x[1]
for i in x[i]:
if x[i] > current_max:
current_max = x[i]
When I run the code, it gives me no errors, but when I try to run max() it'll only accept one argument. The only idea that came to mind was adding in:
x = input('Enter numbers to compare:')
When I ran this, I got:
UnboundLocalError: local variable 'i' referenced before assignment
And I'm unsure of what I can do at this point as I'm unsure of whether or not I'm not defining the argument correctly or there's just an error in the code defining max(x) that didn't show up in the first time for some reason.
Two things:
1) In Python, you need to add a single * before the argument to indicate that the argument is actually a list of arguments. Without that *, you're function is only going to expect a single argument. EDIT: Ah I just saw you are actually passing a list object into your function, in which case the * isn't needed. If you wanted to support a call such as max(1,3,7,-4) then you would indeed want a *.
2) When iterating through a list, or any other "iterable", you can use for item in list_of_items: to iterate over and examine each item in the list. This is used all the time in Python and is the preferred way (ie. the Pythonic way) to iterate over the list of args in a case such as this.
Here's an example max function that ties it all together (and supports a call such as max(1,5,7,3):
def max(*x):
current_max = x[0] # Note we're assuming at least one argument was passed in. What if nothing was passed in?
for i in x:
if i > current_max:
current_max = i
return current_max
And here's an example max function that supports a call such as max([1,5,7,3]):
def max(x):
current_max = x[0] # Note we're assuming at least one argument was passed in. What if nothing was passed in?
for i in x:
if i > current_max:
current_max = i
return current_max
FYI My examples are not the best solutions to this problem, so I suggest you expand on them for your final solution.
x[i] is executed before the loop is for processed by the compiler so trying to loop through x[i] without i being declared beforehand will result in an error.
Given x where x is the list x = [ 1,2,3,4 ] the following should work
def max(x):
current_max = x[0]
for i in x:
if i > current_max:
current_max = i
return current_max
x = [1,2,3,4]
print max(x)
Your algorithm will work but there are two small problems. First, there is a problem with iterating over an array. Normally you don't need indexes at all, just do:
some_list = [1, 2, 3]
for item in some_list:
print item
# Will print 1, then 2 and finally 3
Also you need to return current_max when you are done with your loop.
Reusing names of builtin functions is not a great idea, so I'd call it my_max or something like that. If you also want to check your arguments and add a docstring, you'll end up with this:
def my_max(x):
""" Return the biggest item in an iterable. """
if len(x) == 0:
raise ValueError("my_max() arg is an empty sequence")
current_max = x[0]
for i in x:
if i > current_max:
current_max = i
return current_max
If you prefer a functional coding style, you can use reduce to reduce your list to the biggest element. Simply define the lambda that returns the biggest element:
def my_max(xs):
return reduce(lambda x, y: x if x > y else y, xs)
If you wonder how Python's built-in max is defined, it's actually written in C like many of Python's built-in functions. You can check it out on GitHub if you're curious. Internally it works just as min, since comparisons are done using something called PyObject_RichCompareBool that can compare two objects in different ways (less, less or equal, equal, not equal, ...)
Related
I'm trying to get the minimum odd number using python. I used lambda, loops and other methods to get minimum odd number but i was not able to get that using functions. here is my code
z= [1,8,-4,-9]
def min_odd(x):
for i in x:
if (i%2!=0):
return min(i)
y = min_odd(z)
print (y)
Can some please tell me what i was missing here.
The min() function expects an iterable like a list which it will then yield the smallest element from.
E.g. min([1,0,3]) gives 0.
So if you want to use it, you must create a list (or other iterable) of the odd numbers that you can then pass into it:
def min_odd(x):
odds = []
for i in x:
if i % 2 != 0:
odds.append(i)
return min(odds)
note that we could also use a list-comprehension:
def min_odd(x):
return min([i for i in x if i % 2 != 0])
which both work.
An alternative method would be to store the current minimum odd value in a variable and update this variable if we come across a smaller odd value:
def min_odd(x):
min_v = float('inf')
for i in x:
if i % 2 != 0 and i < min_v:
min_v = i
return min_v
Try:
min([val for val in z if val % 2 != 0])
It seems your code logics are wrong. First off, you seem to have an indentation error in the return statement. Second off, the min() function requires a collection of items (like an array for example) or a series of arguments to determine the minimum in that series. You can try multiple things.
Use another variable to store a temporary minimum. Replace it every time you find a smaller odd value ( for every i in x... if the value is odd and is smaller than the previous odd value, replace it) and have it started with the first odd number you can find.
Take all the odd numbers and add them to another array on which you will apply the min function.
Hope this proves useful!
You could pass a generator into the min() function:
def min_odd(iterable):
return min(i for i in iterable if i % 2)
I didn't write i % 2 != 0 because any odd number will return 1 which has a Boolean value of True.
I added a parameter to the function that takes the iterable so it can be used for any iterable passed in.
min operates on an iterable. i is not an iterable in your code; it's the last element of the list.
You can achieve what you want with a filter, though:
min(filter(lambda e: e%2 != 0, x))
I'm kinda new to Programming and Python and I'm self learning before going to uni so please be gentle, I'm a newbie. I hope my english won't have too many grammatical errors.
Basically I had this exercise in a book I'm currently reading to take a list of tuples as a function parameter, then take every item in the each tuple and put it to 2nd power and sum the items up.
My code looks like this and works good if my function call includes the same amount of arguments as the function for loop requires:
def summary(xs):
for x,y,z in xs:
print( x*x + y*y + z*z)
xs =[(2,3,4), (2,-3,4), (1,2,3)]
summary(xs)
However, If I use a list with less tuples than the function definition, I get an error: ValueError : not enough values to unpack(expected 3, got 0):
xs =[(2,3,4), (), (1,2,3)]
I would like to know how to make a function that would accept a tuple I shown before () - with no tuples, and the function would return 0. I have been trying multiple ways how to solve this for 2 days already and googling as well, but it occurs to me I'm either missing something or I'm not aware of a function i could use. Thank you all for the help.
One way is to iterate over the tuple values, this would also be the way to tackle this problem in nearly every programming language:
def summary(xs):
for item in xs:
s = 0
for value in item:
s += value**2
print(s)
Or using a list comprehension:
def summary(xs):
for item in xs:
result = sum([x**2 for x in item])
print(result)
also note that sum([]) will return 0 for an empty iterable.
Well, the issue is that you don't have enough indices in your inner tuple to unpack into three variables. The simplest way to go around it is to manually unpack after checking that you have enough variables, i.e.:
def summary(xs):
for values in xs:
if values and len(values) == 3:
x, y, z = values # or don't unpack, refer to them by index, i.e. v[0], v[1]...
print(x*x + y*y + z*z)
else:
print(0)
Or use a try..except block:
def summary(xs):
for values in xs:
try:
x, y, z = values # or don't unpack, refer to them by index, i.e. v[0], v[1]...
print(x*x + y*y + z*z)
except ValueError: # check for IndexError if not unpacking
print(0)
One way is to use try / except. In the below example, we use a generator and catch occasions when unpacking fails with ValueError and yield 0.
While you are learning, I highly recommend you practice writing functions which return or yield rather than using them to print values.
def summary(xs):
for item in xs:
try:
yield sum(i**2 for i in item)
except ValueError:
yield 0
xs = [(2,3,4), (), (1,2,3)]
res = list(summary(xs))
print(res)
[29, 0, 14]
Or to actually utilise the generator in a lazy fashion:
for i in summary(xs):
print(i)
29
0
14
You should use the "len > 0" condition. This code should work for any list or tuple length :
def summary(xs):
for tup in xs:
prod = [a*a for a in tup if len(tup)>0]
print(sum(prod))
Note that I defined a "prod" list in order to use "sum" so that it is not calculated the hard way. It replaces your "x* x + y* y + z* z" and works for any tuple length.
It often pays to separate your algorithm into functions that just do one thing. In this case a function to sum the squares of a list of values and a function to print them. It is very helpful to keep your variable names meaningful. In this case your xs is a list of lists, so might be better named xss
import math
def sum_of_squares(xs):
return sum(map(math.sqr, xs))
def summary(xss):
for xs in xss:
print sum_of_squares(xs)
xss = [(2,3,4), (), (1,2,3)]
summary(xss)
or
map(print, sum(map(math.sqr, (x for x in xs))))
I have the following recursive function:
def recurse(y,n):
if len(y) == n:
return y
else:
return recurse(y.append(1),n)
When I run it:
x=recurse([],10)
I get the following error:
TypeError: object of type 'NoneType' has no len()
It seems that the function gets past the if statement the 1st time around, then it goes into the next level of recursion, and there, y.append(1) is 'NoneType', why is it not: '[1]' as expected? I have thought about this for a while and I can't seem to figure it out. Any insight is appreciated!
The problem is here:
y.append(1)
The append() method returns None, so you can't pass its result for building the output list (you'd have to first append to the list and then pass it, as shown in other answers). Try this instead:
def recurse(y, n):
if len(y) == n:
return y
else:
return recurse(y + [1], n)
The above solution is more in line with a functional programming style. Using append adds an element to an existing list - which will mutate a function parameter, in general not a very good idea. On the other hand y + [1] creates a new list each time, leaving the parameter untouched. Proponents of functional programming will tell you that's a Good Thing.
list.append() calls the append method on a list, and while it modifies the list, it returns None.
So it does not return the list.
You want something like:
def recurse(y,n):
if len(y) == n:
return y
else:
y.append(1)
return recurse(y,n) # explicitly pass the list itself
y.append operates on y in place and returns None
Please tell me why this sort function for Python isnt working :)
def sort(list):
if len(list)==0:
return list
elif len(list)==1:
return list
else:
for b in range(1,len(list)):
if list[b-1]>list[b]:
print (list[b-1])
hold = list[b-1]
list[b-1]=list[b]
list[b] = hold
a = [1,2,13,131,1,3,4]
print (sort(a))
It looks like you're attempting to implement a neighbor-sort algorithm. You need to repeat the loop N times. Since you only loop through the array once, you end up with the largest element being in its place (i.e., in the last index), but the rest is left unsorted.
You could debug your algorithm on your own, using pdb.
Or, you could use python's built-in sorting.
Lets take a look at you code. Sort is a built in Python function (at least I believe it is the same for both 2.7 and 3.X) So when you are making your own functions try to stay away from name that function with inbuilt functions unless you are going to override them (Which is a whole different topic.) This idea also applies to the parameter that you used. list is a type in the python language AKA you will not be able to use that variable name. Now for some work on your code after you change all the variables and etc...
When you are going through your function you only will swap is the 2 selected elements are next to each other when needed. This will not work with all list combinations. You have to be able to check that the current i that you are at is in the correct place. So if the end element is the lowest in the List then you have to have it swap all the way to the front of the list. There are many ways of sorting (ie. Quick sort, MergeSort,Bubble Sort) and this isnt the best way... :) Here is some help:
def sortThis(L):
if (len(L) == 0 or len(L) == 1):
return list
else:
for i in range(len(L)):
value = L[i]
j = i - 1
while (j >= 0) and (L[j] > value):
L[j+1] = L[j]
j -= 1
L[j+1] = value
a = [1,2,13,131,1,3,4]
sortThis(a)
print a
Take a look at this for more sorting Fun: QuickSort MergeSort
If it works, it would be the best sorting algotithm in the world (O(n)). Your algorithm only puts the greatest element at the end of the list. you have to apply recursively your function to list[:-1].
You should not use python reserved words
Full disclosure: this is for an assignment. Simply getting working code is enough, but doing this in three lines gets me extra credit.
I'm trying to take a 1000-digit string and find the largest product of 5 consecutive digits. You may recognize this as Project Euler's Problem #8.
I've tried a lot of options, but I seem to be stuck. I'm working on figuring out if I can make a lambda statement that will work, but I have no experience with lambda so it's evading me.
Here's what I have so far:
for i in range(1, 996):
max = int(number[i+0]) * int(number[i+1]) * int(number[i+2]) * int(number[i+3]) * int(number[i+4]) if max < int(number[i+0]) * int(number[i+1]) * int(number[i+2]) * int(number[i+3]) * int(number[i+4]) else max = max
return max
That doesn't work and triggers SyntaxError: can't assign to conditional expression.
I don't want outright code, or at least not a complete function, but just a little help understanding how I can move forward.
This isn't legal python:
x = y if z else x = w
This is:
x = y if z else w
So is this:
if z: x = y
By the way, there is a one line solution, that is much shorter and clearer than your three.
= appears twice in your (very long) line. Effectively you have this:
max = something if something else max = max
which Python parses as:
max = (something if something else max) = max
And, indeed, you can't assign to a conditional expression, which is that whole thing in the middle.
You probably didn't intend to have the final = max at the end.
In [15]: def myinput(l,n):
...: for x in l:
...: yield l[x:x+n]
...:
In [16]: max([reduce(lambda a,b:a*b, x) for x in myinput(range(1000),5) if len(x)==5])
Out[16]: 985084775273880L
Like recursive mentioned, there is a simple one-liner solution. It involves using the max function - always bad to name variables after builtins!
In Python 2 it looks something like this:
max(reduce(lambda x, y: x*y, map(int, num[i:i+5])) for i in xrange(996))
In Python 3 reduce was removed, so you have to get it through functools:
from functools import reduce
max(reduce(lambda x, y: x*y, map(int, num[i:i+5])) for i in range(996))
Look into:
the built-in max function to find the greatest number in a sequence,
the built-in map function to apply a function to all elements in a list,
the built-in reduce function to obtain a single object as a result of applying a function that returns a single object repeatedly to two elements in a list,
lambda definitions to be able to define function objects that you can pass to map() and reduce(),
and list comprehensions (and generators, which are very similar) to compose the above functions in a one-liner.