How to fix 'int object is not iterable' - python

I'm trying to add all the integers in the 'a' variable, but this 'a' variable isn't working as a list nor a string, despite having various different integers in it.
I'm writing a Python program that given a positive integer num, provided by the user, prints the sum of all its divisors.
I've already tried to make this 'a' variable a list but the same error happens
import math
num = int(input("Num: "))
a = num + 1 # because range excludes the last number
b = range(1, a)
for i in (b):
x = num / i
if math.floor(x) == x:
c = list(i)
I've already tried to make this 'a' variable a list but the same error happens: 'int object is not iterable'

list() creates a new list, and its argument must be an iterable (e.g. a tuple, another list, etc.). If you only pass one number, i, it won't work.
I suppose what you want to do is not to create a new list with each loop iteration, but add the i element to an already existing list.
You can achieve it this way:
num = int(input("Num: "))
a = num + 1 # because range excludes the last number
b = range(1, a)
divisors = [] # create a new list where the results will be stored
for i in (b):
x = num / i
if math.floor(x) == x:
divisors.append(i) # add the number at the end of the list
If you want to sum all the divisors, use:
sum(divisors)
An even more 'Pythonic' (though, admittedly, not necessarily easier to read if you're not used to list comprehensions) way to achieve the same result would be:
num = int(input("Num: "))
divisors_sum = sum(i for i in range(1, num + 1) if num//i == num/i)
I assume you're using Python 3 here. In Python 3, // is floor division, so you don't have to use math.floor. See this post for more details on // vs. /.

You can create an empty list outside of the loop: c = [], and then each time append an element to the list by c.append(i).

Related

How can i know if a list is decreasing? (Python)

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?
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)
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:]))
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.
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))

Need to make a list from a function

I want to change the a variable from 1 to 50 and create an array from the results so that I can feed it into a curve.
The variable is outside the function but the variable changes a value in the function, that is what I need to make a list of.
a=1
def test(foo):
p =a+2
print(p)
test(foo)
I want to get the p values when I change a from 1 to 50:
[3,4,5,6,7,8,9...]
Not sure what you trying to do but if you need a list of numbers with some starting point, you can simply generate them using list comprehension as:
a = 2
x = [i+a for i in range(1, 50)]
print(x)
EDIT: Based on comments from author.
You need to change print to return the generated number. Also, need to add a loop and a list to generate a new number and keep appending the new number to the list.
Note: As said earlier, it is recommended to use Python's supported features like list comprehension as is shown in the original code.
a = 1
def test(i):
p = a + i
return p
res = []
for i in range(2, 50):
res.append(test(i))
print(res)

Why can't this function work to replace elements in a list?

Trying to change all 5's into 100's. I know you should use list comprehension but why doesn't this work? Someone can explain theoretically? Thank you.
d = [5,1,1,1,5]
def f1(seq):
for i in seq:
if i==5:
i = 100
return seq
print (f1(d))
This line:
i = 100
Gives the local variable i, which was originally assigned that value in seq, the value 100.
To change the value in the sequence, you could do:
for index, object in enumerate(seq):
if object == 5:
seq[index] = 100
Enumerate returns two objects each time it is called on a sequence, the index as a number, and the object itself.
See the docs on lists and (Python 2) enumerate.
You could have also written:
for index in range(len(seq)):
if seq[index] == 5:
seq[index] = 100
Which you may prefer, but is sometimes considered less clean.
The Python assignment operator binds a value to a name. Your loop for i in seq binds a value from seq to the local name i on every iteration. i = 100 then binds the value 100 to i. This does not affect the original sequence, and the binding will be changed again in the next iteration of the loop.
You can use enumerate to list the indices along with the values of seq and perform the binding that way:
def f1(seq):
for n, i in enumerate(seq):
if i == 5:
seq[n] = 100
return seq
Even simpler may be to just iterate over the indices:
def f2(seq):
for n in range(len(seq)):
if seq[n] == 5:
seq[n] = 100
return seq
The options shown above will modify the sequence in-place. You do not need to return it except for convenience. There are also options for creating a new sequence based on the old one. You can then rebind the variable d to point to the new sequence and drop the old one.
The easiest and probably most Pythonic method would be using a list comprehension:
d = [5, 1, 1, 1, 5]
d = [100 if x == 5 else x for x in d]
You can also use map:
d = list(map(lambda x: 100 if x == 5 else x, d))
The output of map is a generator, so I have wrapped it in list to retain the same output type. This would not be necessary in Python 2, where map already returns a list.
Take the following example:
def f1(seq):
for i in seq:
if i==5:
i = 100
# at this point (assuming i was 5), i = 100 but seq is still [3,5,7]
# because i is not a reference to the item but the value *copied* from the list
...
f1([3,5,7])
You could instead loop through the indices and set the value at that index in the list:
d = [5,1,1,1,5]
def f1(seq):
for i in range(len(seq)):
if seq[i]==5:
seq[i] = 100
return seq
print(f1(d))
# [100,1,1,1,100]
You should update the element at the list, like that:
def f1(seq):
for i in range(len(seq)): # run through the indexes of the list
if seq[i]==5: # check whether seq at index i is 5
seq[i] = 100 # update the list at the same index to 100
return seq
i is a new variable created inside the loop, therefore it's not the same reference as the element inside the list.
NOTE:
Note that list is a mutable object, therefore changing seq inside the function will affect the list even outside the function.
You can read more about mutable and immutable in here

List index out of range

I'm trying to create my own Hash data structure in python. In __init__ I initialize a list (m_list) of size m and in another function I add hashes to it from my hash function.
I'm now trying to search through the list, looking for value k. I'm getting a list index out of range error on the if self.m_list[i] == k: line.
class Hash:
def __init__ (self, n, m, m_list=None):
self.n = n
self.m = m
self.a = choice(range(1, n))
self.b = choice(range(n))
if m_list is None:
m_list = []
self.m_list = m_list * m
def search(self, k):
found = False
for i in self.m_list:
if i is not None and found is False:
if self.m_list[i] == k:
found = True
if found:
print True
else:
print False
I created m_list using guidelines from Create an empty list in python with certain size
There are multiple problems with this code:
1) Indexing a list with its own contents.
for i in self.m_list:
when you loop on a list in python using this syntax, the value in the variable (i) is the value from in the list, not the index for that iteration.
There are two choices of ways to solve this. If you, for some reason need to have the index, you can loop by using the range function to create the indices and loop over them, like so:
for i in range(len(self.m_list)):
if not found and self.m_list[i] == k:
found = True
Or you can just use python's native iteration over the contents of the list:
for item in self.m_list:
if not found and item == k:
found = True
Another option, if you want easy access to both the index and the value is to use enumerate. enumerate returns tuples containing the index of the value and the value itself, so you can use python's multi-assignment to have access to both:
for i, val in enumerate(self.m_list):
if val == k:
...
if i == some_index
...
The original code will only ever return true if m_list[i] == i == k, so if you indented to check that this condition held, you could just check m_list[k] == k.
2) As noted in Peter's answer, [] * m always gives [], so no matter what the indexes being provided are, the list will have zero length and therefore any index will be out of range. To get a list with length m, you need to have one element in the list to duplicate. You can use None or 0 as that value: [0] * m gives a list of m zeroes, and [None] * m gives a list of m none values.
You are not creating a list of size m. [] * m gives you [], as you can see in an interactive shell. The linked answers show how multiplying a list will shallow copy the contents of the list m times, but of course [] has no contents to copy. Try if m_list is None: m_list = [None] * m or something similar.
Your search method makes no sense to me (there are better ways to store just the existence of integers) but that's a separate problem.

Trying to store array from main to an array in another function

This program should create an array in main and prompts the user to enter 5 integers and store them in the array in a function called fibArray. It then creates a function named containOnlyOdd that excepts the array and returns a true if the array contains only odd numbers or false if it does not. print a message indicating the results such as ex: [1,2,3,4,5] "The array contains both odd and even numbers." or [1,3,5,7,9] "The array contains only odd numbers.
The error is get is in line 10 in fibArray which is fibArray = [0] * num. TypeError: Can't multiply sequence by non-int of type list.
def main():
integer = 5
intArray = [0] * integer
for index in range(integer):
intArray[index] = int(input("Enter integers:"))
print(intArray)
fibArray(intArray)
def fibArray(num):
fibArray = [0] * num
for index in range(num):
print(num)
def containsOnlyOdds(lst):
for num in lst:
if num % 2 == 0
#print("This list is all odd")
return false`
#print("This list has even numbers")
return True
main()
What am I doing wrong? Please help!!
It is exactly, what the error message states: you hand an array to fibArray:
fibArray(intArray)
which in turn tries to multiply it with [0]:
fibArray = [0] * num
You may only call fibArray and pass a number, but not an array.
edit/add:
The numbers are already stored in the array intArray. No need for the function fibArray. Of course you could alternatively pass the numbers to a function which then again stores the values. Since you are just beginning python, i recommend leaving it with the value-checking-function for now. Once the program works, you can try to encapsulate part of the code in another function.
There is also some syntax errors in the definition of def containsOnlyOdds(lst): You should fix the indentation of the loop and if-statement. Also, you are missing a colon after the statement, e.g.
for anElement in aList:
if (statement):
#do something, e.g. return False
#do something else, e.g. return True

Categories

Resources