I am new to python and I have to do an exercise for classes. The exercises asks me to make a function which tells weather a list given is ordered decreasing or not (Giving back True or False) I tried the following code:
def no_decreasing(list):
for num in len(list):
if list[num] <= list[num 1]:
check = bool(1)
else:
check = bool(0)
break
return check
It gives back an te error "int" object is not iterable in line 2, does anyone know why?
CodePudding user response:
Note: don't use list
as the parameter name (it's a builtin type), use something else. I'll use nums
as the place of the list parameter rather than list
.
The expression for num in len(nums)
doesn't work because len(nums)
is a single int. What you would want instead is for num in nums
(which would iterate over each number in nums
, or for index in len(range(nums))
(which would iterate over each valid index into nums
).
Other options:
for i, num in enumerate(nums)
--i
is the index,num
is the value.for num1, num2 in zip(nums, nums[1:])
--num1
andnum2
are two successive values fromnums
, obtained byzip
pingnums
with a shifted version of itself.
Additional note: when you need a boolean literal, instead of bool(1)
and bool(0)
just use True
and False
!
You could also shortcut the entire problem by sorting the list in decreasing order and seeing if it's the same as the original list:
def is_decreasing(nums):
return nums == sorted(nums, reverse=True)
CodePudding user response:
Well you are trying to iterate over indeces, so
for i in range(len(lst)): # never use "list" as a variable name
or rather
for i in range(len(lst)-1): # to avoid an index error for its right neighbor
would be appropriate. However, a better way would use zip
def non_decreasing(lst):
for a, b in zip(lst, lst[1:]):
if b < a:
return False
return True
A short-hand for that pattern is any
or all
:
def non_decreasing(lst):
return all(a <= b for a, b in zip(lst, lst[1:]))
# return not any(b < a for a, b in zip(lst, lst[1:]))
CodePudding user response:
You are trying to get the index in the for
loop, but you've made a semantic mistake:
for num in len(list):
# This does not work. It can not iterate through an integer.
len()
function returns an integer. Your basically saying for num in 10
, say if the list has 10 numbers.
What you want is the range
function:
for num in range(0, len(list)):
This will loop from num=0
to num=0 len(list)-1
.
Be careful though with if list[num] <= list[num 1]:
, as the previous approach will make that line search for an index greater them your array size. As such, this is how you could fix your code:
for num in range(0, len(list)-1):
P.S.: There are other ways to solve that issue, but since it is a class exercise, I've focused on solving the issue you've had when iterating through an integer.
CodePudding user response:
Others have pointed out using zip(lst, lst[1:])
. This is undesirable for large lists, though, since you first have to make a copy of lst
(minus the first element) before zip
can produce the pairwise iterator that the for
loop uses.
Instead, use two separate iterators, advancing the second one before passing it to zip
.
def no_decreasing(lst):
i1 = iter(lst)
i2 = iter(lst)
next(i2)
return all(a >= b for a, b in zip(i1, i2))
# Or you can use map
# return all(map(operator.ge, i1, i2))