list index out of range in simple Python script - python

I just started learning Python and want to create a simple script that will read integer numbers from user input and print their sum.
The code that I wrote is
inflow = list(map(int, input().split(" ")))
result = 1
for i in inflow:
result += inflow[i]
print(result)
It gives me an error
IndexError: list index out of range
pointing to result += inflow[i] line. Can't see what am I doing wrong?
BTW, is there more elegant way to split input flow to the list of integers?

You can also avoid the loop altogether:
inflow = '1 2 34 5'
Then
sum(map(int, inflow.split()))
will give the expected value
42
EDIT:
As you initialize your result with 1 and not 0, you can then also simply do:
sum(map(int, input.split()), 1)
My answer assumes that the input is always valid. If you want to catch invalid inputs, check Anton vBR's answer.

Considering: I just started learning Python
I'd suggest something like this, which handle input errors:
inflow = raw_input("Type numbers (e.g. '1 3 5') ") #in py3 input()
#inflow = '1 2 34 5'
try:
nums = map(int, inflow.split())
result = sum(nums)
print(result)
except ValueError:
print("Not a valid input")

for i in list gives the values of the list, not the index.
inflow = list(map(int, input().split(" ")))
result = 1
for i in inflow:
result += i
print(result)
If you wanted the index and not the value:
inflow = list(map(int, input().split(" ")))
result = 1
for i in range(len(inflow)):
result += inflow[i]
print(result)
And finally, if you wanted both:
for index, value in enumerate(inflow):

script that will read integer numbers from user input and print their
sum.
try this :
inflow = list(map(int, input().split(" ")))
result = 0
for i in inflow:
result += i
print(result)

If you were going to index the list object you would do:
for i in range(len(inflow)):
result += inflow[i]
However, you are already mapping int and turning the map object into a list so thus you can just iterate over it and add up its elements:
for i in inflow:
result += i
As to your second question, since you arent doing any type testing upon cast (i.e. what happens if a user supplies 3.14159; in that case int() on a str that represents a float throws a ValueError), you can wrap it all up like so:
inflow = [int(x) for x in input().split(' ')] # input() returns `str` so just cast `int`
result = 1
for i in inflow:
result += i
print(result)
To be safe and ensure inputs are valid, I'd add a function to test type casting before building the list with the aforementioned list comprehension:
def typ(x):
try:
int(x)
return True # cast worked
except ValueError:
return False # invalid cast
inflow = [x for x in input().split(' ') in typ(x)]
result = 1
for i in inflow:
result += i
print(result)
So if a user supplies '1 2 3 4.5 5 6.3 7', inflow = [1, 2, 3, 5, 7].

What your code is doing, in chronological order, is this:
Gather user input, split per space and convert to integer, and lastly store in inflow
Initialize result to 1
Iterate over every item in inflow and set item to i
Add the current item, i to result and continue
After loop is done, print the result total.
The broken logic would be at step 4.
To answer your question, the problem is that you're not gathering the index from the list as expected-- you're iterating over each value in the list opposed to the index, so it's really undefined behavior based on what the user inputs. Though of course, it isn't what you want.
What you'd want to do is:
inflow = list(map(int, input().split(" ")))
result = 1
for i in range(len(inflow)):
result += inflow[i]
print(result)
And on your last regard; there are two real ways to do it, one being the way you're doing right now using list, map and:
inflow = [int(v) for v in input().split()]
IMO the latter looks better. Also a suggestion; you could call stdlib function sum(<iterable>) over a list of integers or floats and it'll add each number and return the summation, which would appear more clean over a for loop.
Note: if you're splitting per whitespace you can just call the str.split() function without any parameters, as it'll split at every whitespace regardless.
>>> "hello world!".split()
['hello', 'world!']
Note: also if you want extra verification you could add a bit more logic to the list comprehension:
inflow = [int(v) for v in input().split() if v.isdigit()]
Which checks whether the user inputted valid data, and if not, skip past the data and check the following.

Related

Reading an array from stdin using input() function throws an EOF error

Basically, I wish to sum the elements of the array provided in stdin. Why is it saying that list index is out of range? Is there anything special about the python input() function?
length = int(input())
li = []
for i in range(0, length):
li[i] = int(input())
sum = 0
for item in li:
sum = sum + item
Input
first line : length of array
second line : elements of the array.
EDIT : second line is a single string, not space separated integers.
3
1 2 3
Output:
Traceback (most recent call last):
File "./prog.py", line 6, in <module>
IndexError: list assignment index out of range
your question pretty much got answered, I just wanna show you a couple of tricks to make your program more simple and pythonic.
Instead of the for-loop try:
li = [int(i) for i in input().split(" ")]
And instead of the way you're calculating sum, try:
sum(li)
or even better:
sumOfItems = sum(int(i) for i in input().split(" "))
The thing with python lists is that you cannot assign a particular value to a position when that position originally does not exist, that is, the length of the list is less than the position that you want to change.
What you are trying to do is assign the value to a particular position in the list (called index) but since the list is empty, it's length is 0 and hence the index is out of range( that is it is not available for modifiying. That is why python is raising Index out of range error.
What you can try is:
l=[]
length=int(input())
for i in length:
l.append(int(input())
sum=0
for num in l:
sum=sum+num
You can solve this in a single line without even taking in the length. But you have to enter space separated values in a single line:
s = 0
for item in list(map(int, input ().split())):
s += item
If you want to input one integer per line, then you'll need the length(or a sentinel value):
s = 0
len = int(input())
li = [int(input ()) for _ in range(len)]
for item in li:
s = s + item
The second line of input turned out to be a single string and not space separated integers.
So I had to split the string, then convert the strings to integers to calculate their sum. Some of the methods mentioned above didn't work.
The list comprehension method will work in the space separated case, and is perfectly fine.
length = int(input())
l = input().split() # List of strings of integers.
S = 0
for item in l:
S += int(item) # Converting string to int
print(S)
You can't assign values to locations of a list that doesn't exist
try this:
length = int(input())
li = list(range(length))
for i in range(0, length):
li[i] = int(input())
sum = 0
for item in li:
sum = sum + item
you can also do something like this:
length = int(input())
li = []
for i in range(0, length):
li.append(int(input()))
total = sum(li)
print(total)

Taking single value input in Python

I was attempting to do one kata problem in Python, where I have two lists of input, let's say weight and value, which was getting input in the order (value1, weight1, value2, weight2,....)
If it were C++, I could just take one element at a time with cin to my arrays. But with Python I don't know how to take this input.
If the input is like
60 10 100 20 120 30 (in a single line)
I want my two lists val and w have values
val=[60,100,120]
w=[10,20,30]
How to take this kind of inputs in Python? Is it possible to read only one input at a time, like cin does in C++?
You can read space-separated input to a list using splitand then use slicing to get the odd/even indexed elements:
val = input().split()
val = [int(i) for i in val] #to integer
w = val[1::2] # get only odd indices
val = val[0::2] # get only even indices
print(val) # [60,100,120]
print(w) # [10,20,30]
You can then use regular indexing to get individual elements in the lists.
This should do it.
values = input("Enter values: ").split(" ")
if(len(values) % 2 != 0):
print("Error, uneven number of values and weights")
else:
val = []
w = []
for i in range(0, len(values) - 1, 2):
val.append(values[i])
w.append(values[i+1])
print("val: ", val)
print("w: ", w)
No you cannot as far as I know. input() is a function that reads one line at a time as an entire string.
A popular way to make a list out of an entire line of space separated integers is using the in-built map() function and split() method of a string object:
numbers = map(int, input.split())
numbers will now contain the list of numbers on that line.
Firstly, input() reads the entire line as a string including spaces.
split() function splits the input at space, you can also pass in a string argument to make it split anywhere you want, i.e a custom delimiter like , and creates a list of strings of those numbers
map() calls int() on each of the numbers in that list.
In C++, just like you need to know the size of input in advance, you can run a for loop on the list to now split values and weights into two lists.
val, w = [], []
for i in range(len(numbers)):
if i % 2 == 0: val.append(numbers[i])
else: w.append(numbers[i])
For better performance(relevant for large input size), you can even skip the map() step, and do something like this:
numbers = input().split()
val, w = [], []
for i in range(len(numbers)):
if i % 2 == 0: val.append(int(numbers[i]))
else: w.append(int(numbers[i]))
Here's a simple solution:
a = "60 10 100 20 120 30"
split_a = a.split(" ")
val = [e for (i, e) in enumerate(split_a) if i % 2 == 0]
w = [e for (i, e) in enumerate(split_a) if i % 2 == 1]
# or shorter with slicing (start:stop:step)
val = [e for e in split_a[0::2]]
w = [e for e in split_a[1::2]]
I am not sure what cin does but I assume the input you have is a string. One way you could do is to split it into a list of ints. And then create your val and w lists and append your values into the lists. (The first, third, fifth, etc would be your val list)
my_input_list = my_input.split(' ')
Read more here.

Eliminate numbers between 1 and 100 present in list

I have written a code that should input numbers from the user and report back the numbers from 1 to 100 that are missing from their input.
My code is below which doesn't work:
num_list = []
number = input('Enter numbers (remember a space): ')
number.split()
num_list.append(number)
for i in range(1, 101):
if i in num_list:
continue
else:
print(i, end =', ')
The code outputs all the numbers from 1 to 100 but doesn't exclude the numbers.
Note: The code has to exclude all the numbers entered not only one number.
E.g. if the user inputted 1 2 3 4 the output should start from 5 and list the numbers through to 100.
There are three of problems
1) your are not saving the returned list from split method
result = number.split()
2) Use extend instead of append
num_list.extend(result)
3) By default input will read everything as string, you need to convert them into int from string after splitting, below is example using List Comprehensions
result = [int(x) for x in number.split()]
append : Will just add an item to the end of the list
So in you case after appending user input your list will be
num_list.append(number) #[[1,2,3,4,5]] so use extend
extend : Extend the list by appending all the items from the iterable.
num_list.append(number) #[1,2,3,4,5]
Note : If the num_list empty you can directly use result from split method, no need of extend

How to ask the user to enter numbers and then sum the numbers which are divisible by 3?

I want to make a Python script which has the user enter 7 numbers and then check which numbers can be divided by 3, then sum those numbers, and show it to the user as "sum=xx".
I tried:
input_string = input("Enter a list element separated by space ")
list = input_string.split()
Here is using list comprehension,
input_string = input("Enter a list element separated by space ")
numbers = [int(num) for num in input_string.split(',') if int(num) % 3 == 0]
print('Sum = {}'.format(sum(numbers)))
This is based on your question above.
But, you also said that you would want user to input 7 numbers and find sum for numbers which are divisible by 3.
Here is other simple example, where we ask user to input 7 numbers, one number at a time and print sum at the end.
all_numbers = []
for i in range(7):
num = int(input(f'Enter number {i + 1}:\n1'))
all_numbers.append(num)
sum_of_numbers = sum([num for num in all_numbers if num % 3 == 0])
print(f'Sum = {sum_of_numbers}')
You can get a list of integers from the input using the int function which gives you an integer object from a string, since the split function only gives you a list of separated strings.
input_string = input("Enter a list element separated by space ")
my_list = input_string.split()
numbers = []
for n in my_list:
numbers.append(int(n))
However, this will throw a ValueError if n is not a valid number (e.g. "a"), which you can catch with a try-exceptstatement.
Notice how I changed the name of your variable to my_list because the name list already has a meaning in Python and it's a good practice to not assign it to a variable.
If you want to do it in a single step, you can use the useful map function to apply the int function to all of the elements in list. You can check the documentation for this function, as well as any other on the python documentation, or using the help built-in function. (e.g. help(map))
numbers = map(int, my_list)
You can then check if there are 7 numbers in the list by using the len function, and if there aren't 7 you can prompt the user to input the numbers again if that is what you want to do.
>>> my_list = [1, 2, 3]
>>> len(my_list) == 3
True
If you want to keep prompting the user until there are seven numbers on your list, you can put the prompt inside a while block, like shown:
numbers = [] # We create an empty list
while len(numbers) != 7:
input_string = input("Enter a list element separated by space ")
my_list = input_string.split()
numbers = list(map(int, my_list)) # Get the numbers
After getting the numbers, you can see which ones are divisible by 3 by using the modulo operator, which gives you the rest of dividing a number by another (3 in your case). Some examples:
>>> 7%3 # 7 = 3*2 + 1
1
>>> 19%5 # 14 = 5*3 + 4
4
>>> 8%4 # 8 = 4*2 + 0
0
Since you want to check which numbers of your list are divisible by 3 you can check whether this module is 0 or not inside of a loop through the list.
If the numbers are divisible by 3, you can add them to a counting variable, you could initialize to 0 before the loop. That way, after the loop you'd get the sum you want in this variable.
Another, more elegant way of doing so is using a list comprehension instead of a loop, which would only retain the numbers divisible by 3, and then sum its elements using the sum function.
new_list = [x for x in numbers if x%3 == 0]
sum = sum(new_list)

Python: unorderable types: int() < range() or 'int' object is not iterable

I'm trying to get a python script to print '#' symbols, in relation the the value held in a list. For example, if the list as [1,2,3] - the script would print:
1 #
2 ##
3 ###
With the following code:
myList = [0,1,2,3,4,5,6]
x = 1
While x < range(len(myList)):
print (x, end ='')
for frequency in myList[x]:
print ('#')
print ('\n')
x = x + 1
So far I get this error "TypeError: unorderable types: int() < range()". I think I'm getting this because it can't compare a single number to a range of numbers.
But when I try to just use:
len(myList)
I get: "TypeError: 'int' object is not iterable".
Not sure what to do!
As the error says, this is comparing the value in x to the value range(...):
while x < range(len(myList)):
print (x, end ='')
That's not what you want. Instead, you want to loop across those values:
for x in range(len(myList)):
...
Similarly, your second loop isn't going to work:
for frequency in myList[x]:
print ('#')
Since myList[x] is an int, that translates as "for every value frequency in the the number myList[x]..." which doesn't really make sense. You really mean:
for frequency in range(myList[x]):
print ('#')
Please throw your code in the dustbin and look for a better approach
You'd better do this:
for number in yourList:
if number <= 0:
print("Cannot use negative numbers or zero here!")
else:
print ("{} {}".format(number, "#" * number))
Don't forget that you can get N copies of a string by simply multiplying this string by N, where N is a positive non-zero number.
You're getting the error because you are actually comparing an int to a range object on this line:
while x < range(len(myList)):
To get the output you desire, it would be much easier to just multiply strings:
for i in range(7):
print(i, i * '#')
Adjust the call to range if you want to omit the zero row.
You can use a for loop to do this:
>>> myList = [0,1,2,3,4,5,6]
>>> for item in myList:
... if item > 0:
... print(item, '#' * item)
...
1 #
2 ##
3 ###
4 ####
5 #####
6 ######
In python you can use the '*' operator to print strings multiple times, like a kind of multiplication.
If you want output a zero but no '#' when the item is zero, remove the if item > 0: and dedent the line that follows it.

Categories

Resources