Home > Back-end >  How can i know if a list is decreasing? (Python)
How can i know if a list is decreasing? (Python)

Time:10-15

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 and num2 are two successive values from nums, obtained by zipping nums 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))
  • Related