def AddVct(Vct1,Vct2,VctLen):
Vct3 = []
n=1
while n < VctLen:
Vct3[n] = Vct1[n] + Vct2[n]
n += 1
print(Vct[n])
return Vct3
The program outputs:
IndexError: list assignment index out of range.
How to avoid this?
You can't assign to a list element that doesn't exist. And since you start with an empty list, no elements exist in it. Generally, you would append() instead.
Vct3.append(Vct1[n] + Vct2[n])
Or, you could initialize Vct3 to be the size you want beforehand:
Vct3 = [0] * VctLen + 1
Then the assignment you already have works fine.
Assuming you start with an empty list and use append(), list indices start at 0, so you should define Vct3 as a single-element list so that the indices match between the input and output lists.
Vct3 = [None] # or whatever you want the first value to be
Or else initialize n to 0 instead of 1 if you want to consider all the elements of the lists.
In that case, however, it would be more Pythonic to use a list comprehension
Vct3 = [a + b for (a, b) in zip(Vct1, Vct2)]
N. B. It's generally not necessary to pass in the length of a list as its own parameter. You can trivially get it using len().
Related
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
I am reading a snippet of Python code and there is one thing I can't understand. a is a list, num is an integer
a += num,
works but
a += num
won't work. Can anyone explain this to me?
First of all, it is important to note here that a += 1, works differently than a = a + 1, in this case. (a = a + 1, and a = a + (1,) are both throwing a TypeError because you can't concatenate a list and a tuple, but you you can extend a list with a tuple.)
+= calls the lists __iadd__ method, which calls list.extend and then returns the original list itself.
1, is a tuple of length one, so what you are doing is
>>> a = []
>>> a.extend((1,))
>>> a
[1]
which just looks weird because of the length one tuple. But it works just like extending a list with a tuple of any length:
>>> a.extend((2,3,4))
>>> a
[1, 2, 3, 4]
The trailing comma makes the right side of the assignment into a tuple, not an integer. A tuple is a container structure similar to a list (with some differences). For example, these two are equivalent:
a += num,
a += (num, )
Python allows you to add a tuple to a list and will append each element of the tuple to the list. It doesn't allow you to add a single integer to a list, you have to use append for that.
using
num,
declares a tuple of length one, and not an integer.
Thus, if a = [0,1] and num = 2
a+=num,
is equivalent to
a.extend((num,))
or
a.extend((2,))=[0,1,2]
while
a+=num
is equivalent to
a.extend(num)
or
a.extend(2)
which gives an error, because you can append a tuple to an array, but not an integer. Thus the first formulation works while the second gives you an error
Python provides slicing functionality for lists, but for this
question, you will implement your own function capable of producing
list slices (note: you cannot use the slicing operator in your
solution). The function should be called slice and take the following
three inputs in this specific order:
A list, source, which the slice will be created from. This list cannot be modified by your function.
A positive integer, start, representing the starting index of the slice you will create. If this value is not in the range [0, len(list)-1], your function should return an empty list.
A positive integer, end, representing the ending index of the slice you will create. If this value is not in the range [start, len(list)-1], your function should return an empty list.
If the
parameter values are acceptable, your function will return a list that
contains the items from source beginning at the index start and ending
at the index end (inclusive). This is different from the Python slice
operator, as the item at the index end is also included in the new
list.
This is what I got so far:
list1 = []
def slice(list1):
list1 = list(input("enter a list"))
emptylist = []
st = int(input("enter start"))
ed = int(input("enter end"))
if ed not in range(st,len(list1)-1) or st not in range(0,len(list1)-1):
print(emptylist)
else:
list2 = []
for i in list1:
list2.append(list1[i])
return(list2)
print(slice(list1))
I don't know how the list input is supposed to be delimited, so I'm not going to include it in my answer. In fact, I'm just going to assume that we have somehow received a list of proper format from the user and only need to call the function on that list.
Your function would take 3 parameters, start, end, and the list itself because these are bare minimum requirement for a slicing task.
def slice(lst, start, end):
The simplest solution would be to iterate through the loop and add all the elements within the start:end range. After all, you are allowed to use indexing notation.
You would first have to create an empty list that will contain only the appropriate elements. We'll call this list an output list.
output = []
Then, we can iterate through all the integers between start and end because list indices are integers.
for i in range(start, end):
output.append(lst[i])
At the end of the function, you would want to return the output list so you end up with an actually sliced list object.
return output
Putting it all together:
# some shebangs here
'''
Some docstring here
'''
# some imports here
# receive user input. You need a list and two integers.
# lst = input()
# start = input()
# end = input()
def slice(lst, start, end):
output = []
if not(0 <= start < len(lst)):
return output
elif not(start <= end < len(lst)):
return output
else:
for i in range(start, end+1):
output.append(lst[i])
return output
print(slice(lst, start, end))
Why doesn't your original script work?
Issue with your code is in the last line. If you do:
for i in list1:
list2.append(list1[i])
return(list2)
First of all, i is the element being iterated, not the index of the element. Second, returning terminates the function, and therefore the loop. As a result, not only will the script throw you an IndexError, but even if you're lucky, it will also return a list with only one element. You can modify it like this:
for i in list1:
list2.append(i)
return list2
This would work, except that now we're ignoring the start and end parameters. (This is why I opted for the range() function). If you want to use the Pythonic notation, you would enumerate through the list, check the index, and append if appropriate.
for index, element in enumerate(list1):
if start <= index <= end:
list2.append(element)
return list2
seq_sum = []
for i in range(len(sequence)):
seq_sum[i] = sequence[i] + inv_sequence[i]
print (seq_sum)
When I try to run this code it return an error: list assignment index out of range. How can I fix the problem?
sequence and inv_sequence are arrays of integers.
seq_sum[i] will raise an IndexError as the seq_sum list is empty. You should use append instead:
seq_sum = []
for i in range(len(sequence)):
seq_sum.append(sequence[i] + inv_sequence[i])
print(seq_sum)
You can achieve the same result with a prettier code using list comprehension:
seq_sum = [seq_elem + inv_elem for seq_elem, inv_elem in zip(sequence, inv_sequence)]
You could also use map but some would argue its readability:
import operator
seq_sum = list(map(operator.add, sequence, inv_sequence))
You've declared seq_sum to be an empty list. You then try and index in a position other than 0 which results in an IndexError.
Expanding a list to make it larger is essentially done with appending, extending or slice assignments. Since you sequentially access elements, seq_num.append is the best way to go about this.
That is:
seq_sum[i] = sequence[i] + inv_sequence[i]
Should be instead changed to:
seq_sum.append(sequence[i] + inv_sequence[i])
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.