Problem with "list assignment index out of range" Python - python

I should replace the last element of a tuple in a list of tuples with and object given as input and I tried to write this code but I got a "list assignment index out of range" error at line 4. How should I fix it?
def replaceLast (tupleList, object):
for i, tup in enumerate(tupleList):
lis = list(tup)
lis[-1] = object
tupleList[i] = tuple(lis)
return tupleList
lT=[(1,),(2,3),(),(7,3)]
replaceLast(lT,11) #=> [(11,), (2, 11), (11,), (7, 11)] -> this should be the result

The problem is the empty tuple in your list lT, which does not have a last element, therefore you cannot access it with lst[-1].
Instead of changing lists, create new ones:
def replace_last(tuples, object):
return [
tup[:-1] + (object, )
for tup in tuples
]

your issue is generated when you have empty tuple, then your variable lst will be an empty list so will not make sense to use lst[-1], this will generate your error, a simple fix will be to check if is an empty list:
if lst:
lst[-1] = object
else:
lst.append(object)

Related

Python list comprehension filtering with tuples (containing integers as strings)

I am trying to filter the following list:
tuple = [('7:29', 0.5), ('99:2', 0.35714285714285715), ('10:2', 0.35714285714285715)] using list comprehension, filtering based on the first elements from the tuples between the character ':'.
For example: filter = [7, 99], thus the result would be: new_tuple = [('7:29', 0.5), ('99:2', 0.35714285714285715)].
I tried the following solution:
filter_string = [str(item) for item in filter]
tuple_filtered = [(x,y) for (x,y) in tuples if x in filter]
but it returns an empty list and I don't have any idea how to fix it.
Can somebody please help me?
First when you apply this line:
filter_string = [str(item) for item in filter]
You apply str() function over a tuple object - making all the tuple in to a string.
for example - str(('99:2', 0.35714285714285715)) --> '(\\'99:2\\', 0.35714285714285715)'
Which in my sense just make it harder to parse.
Second, tuple is a saved name in python - do not use it and run it over!
it can cause very annoying bugs later on.
Finally, you can look at a tuple as a fixed size array which is indexed, which mean you can address the first element (that you want to filter by)
Something like that:
my_tuples = [('7:29', 0.5), ('99:2', 0.35714285714285715), ('10:2', 0.35714285714285715)]
my_filter = [7, 99]
filtered_list = [t for t in my_tuples if int(t[0].split(':')[0])
in my_filter]
[(x,y) for (x,y) in tuples if str(x.split(":")[0]) in filter_string ]
Equivalently:
op = []
for (x,y) in tuples :
if str(x.split(":")[0]) in filter_string:
op.append((x,y))

Error: list indices must be integers or slices, not tuple

Trying to read an input that coincides with abjadMapV. Then return the char in AbjadMap. But i keep getting this error.
def show(ln):
abjadMapV=[1,2,3,4,5,6,7,8,9,
10,20,30,40,50,60,70,80,90,
100,200,300,400,500,600,700,800,900,
1000,29]
abjadMap=['\u0627','\u0628','\u062C','\u062F','\u0647','\u0648','\u0632','\u062D','\u0637',
'\u064A','\u0643','\u0644','\u0645','\u0646','\u0633','\u0639','\u0641','\u0635',
'\u0642','\u0631','\u0634','\u062A','\u062B','\u062E','\u0630','\u0636','\u0638',
'\u063A','\uFEFC']
abjadN=["alif","ba","jeem","dal","haa","waw","za","ha","da",
"ya","kahf","laam","meem","noon","seen","ayn","fa","sadh",
"qaf","ra","sheen","ta","tha","kha","thal","dhad","za",
"gayn","lam alif"]
i=0
for i in enumerate(abjadMapV):
if ln in abjadMapV[i] :
print(i)
print(abjadMap[i])
return abjadMap[i]
b=input()
a=show(b)
print(a)
Edited to new code trying to get show to return the index
def show(ln):
abjadMapV=[1,2,3,4,5,6,7,8,9,
10,20,30,40,50,60,70,80,90,
100,200,300,400,500,600,700,800,900,
1000,29]
abjadMap=['\u0627','\u0628','\u062C','\u062F','\u0647','\u0648','\u0632','\u062D','\u0637',
'\u064A','\u0643','\u0644','\u0645','\u0646','\u0633','\u0639','\u0641','\u0635',
'\u0642','\u0631','\u0634','\u062A','\u062B','\u062E','\u0630','\u0636','\u0638',
'\u063A','\uFEFC']
abjadN=["alif","ba","jeem","dal","haa","waw","za","ha","da",
"ya","kahf","laam","meem","noon","seen","ayn","fa","sadh",
"qaf","ra","sheen","ta","tha","kha","thal","dhad","za",
"gayn","lam alif"]
i=0
for i in abjadMapV:
if ln == i:
return abjadMap.index(i)
b=input()
a=show(b)
print(a)
The function enumerate returns tuple. So in line
print(abjadMap[i]) # i here is tuple.
And you have figured out that the list indices must be integer not Tuple.
Therefore edit your code accordingly.
If you are not familiar with enumerate function look at the example given below:
l=['a','b','c']
k=enumerate(l)
enumerate function returns iterable object:
so k is an iterable object,
next(k)
gives the output:
(0,'a')
that means 0 is the index of a in list l.
for i in enumerate(l)
i is an tuple not an integer.
enumerate() returns a list of tuples, each being an index-value pair. You may destructure while iterating through them to solve the issue:
for i,j in enumerate(abjadMapV):
if ln in j: # j is the value i. e. j = abjadMap[i]
print(i) # i is the index
print(abjadMap[i] )
return abjadMap[i]
You may otherwise iterate through range(len(abjadMapV)) and use the variable as the index.

Using Filter Function to categorize list by specific index + Printing by specific index or list name

I am creating and manipulating a list in Python, I am having trouble categorizing my lists via filter function...
I have 3 lists, that I append into one list, I frequently print (the_list) along the way, here is my code:
list1 = ['Georgia', 10.5, 'Peach'];
list2 = ['Florida', 21.3, 'Sunshine'];
list3= ['Alabama', 4.9, 'Dixie'];
#List that includes list1, list2 and list3 called "the_list"
the_list = []
the_list.append(list1)
the_list.append(list2)
the_list.append(list3)
the_list
#insert new values into the list (these values represent state numbers)
list1.insert(3, 4)
list2.insert(3, 27)
list3.insert(3, 22)
#print the modified list
print (the_list)
#Organize the list from lowest to highest (based off numbers in index 1)
the_list.sort(key=lambda tup: tup[1])
print (the_list)
#filter states by category based off their population
#This is where I need help
#Small States
def lessThanTen(index):
return index < 10
the_list
filter(lessThanTen, the_list)
print (the_list)
#Big States
def greaterThanTen(index):
return index > 10
the_list
filter(greaterThanTen, the_list)
print (the_list)
Is there a way to filter these lists into categories by a specific index number, in this case index [1] (Which is population), and subsequently output these list items by printing, either their list name or their value at index [0]...example 'Georgia' or "list1"
Python filter documentation:
filter(function, iterable) Construct an iterator from those elements
of iterable for which function returns true. iterable may be either a
sequence, a container which supports iteration, or an iterator. If
function is None, the identity function is assumed, that is, all
elements of iterable that are false are removed.
Note that filter(function, iterable) is equivalent to the generator
expression (item for item in iterable if function(item)) if function
is not None and (item for item in iterable if item) if function is
None.
It's unclear what you mean, but I'll try to help you the best I can.
First of all: you're greaterThanTen function takes index as input, at least it looks that way. filter doesn't pass index as an argument to greaterThanTen, but rather the element at that index.
Another thing: I don't know if you understand that filter only returns one 'category' as output -- you can only sort one condition at a time. Also, filter doesn't operate on the original list, but creates a new sequence, so filter(greaterThanTen, the_list) doesn't actually change anything. What you should do is: the_list = filter(greaterThanTen, the_list).
If you want to sort by the value at index 1 for each element in the list, you can do this:
filter(lambda element: yourSortFunction(elmenet[1]), list)
This is similar to the function you're using as a key to sort.
Another another thing: Why are you trying to call the_list in greaterThanTen, it makes no sense. The function stops evaluating code after the return statement.
Printing:
If you want to print a value from a specific index in a list just ask for that index.
print(LIST[index])
I hope this helps.
If you want to pass index as argument and maintain some flexibility of your list (you may have population at index other than 1), you can do this
def greaterThanTen(index):
return lambda x: x[index] > 10
def lessThanTen(index):
return lambda x: x[index] < 10
def myfilter(f, L):
return [x[0] for x in filter(f, L)]
print(myfilter(greaterThanTen(1), the_list)) # -> ['Georgia', 'Florida']
print(myfilter(lessThanTen(1), the_list)) # -> ['Alabama']
Or more generically,
import operator
def index_vs_num(index):
ops = {
'>' : operator.gt,
'<' : operator.lt,
'>=': operator.ge,
'<=': operator.le,
'=' : operator.eq
}
return lambda relation: lambda num: lambda x: ops[relation](x[index], num)
greaterThanTwenty = index_vs_num(1)('>')(20)
# the 1st argument is index of your population in the list
# the 2nd argument is the type of comparation
# the 3rd argument is the number to be compared
lessThanFive = index_vs_num(1)('<')(5)
def filter_by_outindex(*index):
def filter_by_f(f, L):
try:
return [x[index[0]] for x in filter(f, L)]
except IndexError:
return list(filter(f, L))
return filter_by_f
myfilter=filter_by_outindex(0)
print(myfilter(greaterThanTwenty, the_list)) # -> ['Florida']
print(myfilter(lessThanFive, the_list)) # -> ['Alabama']
I think this is what you actually want to achieve.
You could probably just do some sort of list comprehension and avoid filtering altogether.
the_final_list = [x for x in the_list if x[1] < 10]
This to me is simpler/more readable and accomplishes your objective.

Convert a list of lists back into a list of tuples

I have a long list that is made up of many tuples (over 100)that all contain 3 items that are strings
first_list = ('the','cat','went'),('back','too','scho'),('t/e','s/e/t','o/ve') etc
Many of the tuples are identically so i am using the set function to get out a unique set
Long_list = set(first_list)
i need the list in its original format , but i also need a duplicate list where the data has been cleaned
I need to remove all the "/" and Replace them with "#"
i can t seem to do this process. Initially i tried creating a foor loop to go through my list and then carry out the find and replace method.
The way i have done it gives me a new list that is made up of items , so the sets of tuples are not retained
for small_tuple in Long_list:
the_list = list(small_tuple)
for uncleaned_string in the_list:
time = uncleaned_string.replace('/','#')
last_list.append(time)
print last_list
Is there a way i can retain my original format of 3 items within tuple when i convert it back ?
tuple(myList) will convert myList into a tuple, provided that myList is something iterable like a list, a tuple, or a generator.
To convert a lists of lists in a list of tuples, using a list comprehension expression:
last_list = [tuple(x) for x in Long_list]
or, to also perform your string replacement:
last_list = [tuple(y.replace('/', '#') for y in x) for x in Long_list]
From Python's reference:
tuple( [iterable] )
Return a tuple whose items are the same and in the same order as iterable‘s items. iterable may be a sequence, a container that supports iteration, or an iterator object. If iterable is already a tuple, it is returned unchanged. For instance, tuple('abc') returns ('a', 'b', 'c') and tuple([1, 2, 3]) returns (1, 2, 3). If no argument is given, returns a new empty tuple, ().
tuple is an immutable sequence type, as documented in Sequence Types — str, unicode, list, tuple, bytearray, buffer, xrange. For other containers see the built in dict, list and [set] classes, and the collections module.
You could do something like the following using a list comprehension converted into a tuple:
for small_tuple in Long_list:
the_list = list(small_tuple)
last_list.append(tuple([uncleaned_string.replace('/','#') for uncleaned_string in the_list]))
print last_list
last_list = [tuple(s.replace('/', '#') for s in t) for t in Long_list]
Modified your code to fit your need
for small_tuple in Long_list:
the_list = list(small_tuple)
res=[]
for uncleaned_string in the_list:
time = uncleaned_string.replace('/','#')
res.append(time)
last_list.append(tuple(res))
print last_list
You can use an OrderedDict to remove the duplicates while preserving the order.
from collections import OrderedDict
x = OrderedDict.fromkeys(first_list)
Long_list = list(x)
Long_list contains unique tuples with order same as of first_list.

Returning list elements and indices [duplicate]

This question already has answers here:
'Return' keyword returns only one element from a loop?
(3 answers)
Closed 8 years ago.
I am trying to print all the elements of a list using a user made function.
y = [1,2,3]
def ash(list1):
for x in range(len(list)):
return list[x],x
what i want to do is return all the values in the list with their indices,but all i get is a single element.I can get the elements to print but not return.
You are returning on the very first iteration. Rather, you need to create a list in your function, and add all the tuples in that list, and finally return that list.
And for getting both index and element, you can use enumerate():
def ash(list1):
new_list = []
for x, elem in enumerate(list1):
new_list.append((elem,x))
return new_list
Or, even better you can simply use List comprehension:
return [(elem, x) for x, elem in enumerate(list1)]
The previous two methods creates the list in memory. If you have a very large list to deal with, then you should probably use generators, using yield keyword:
def ash(list1):
for x, elem in enumerate(list1):
yield elem, x
Some issues with your code:
Don't iterate using range unless necessary. Iterate the list directly, or here, use enumerate
Don't use list as a variable - you'll shadow the built-in of the same name. It's confusing to the reader.
You're returning out of the loop. This is why you only get the first iteration. If you want to return successive values, use yield, which turns your function into a generator:
def ash(l):
for x in range(len(l)):
yield l[x],x
This is really a reimplementation of enumerate:
list(enumerate('abc')) #=> [(0, 'a'), (1, 'b'), (2, 'c')]
If you really want to swap the order of the pairs, you can do:
[b,a for a,b in enumerate('abc')]
Alternative implementation: l='abc';zip(l,xrange(len(l)))
enumerate(list) is what you're looking for. (see doc). Also, calling return will give you only the first value of the list when calling the function, what you want here is probably the yield statement:
def ash(list):
for i,item in enumerate(list):
yield item,i
if __name__ == '__main__':
y = [1,2,3]
ys_with_indices = list(ash(y))
print ys_with_indices
Note that this will return a generator object, which you have to convert to a list by calling list() on it. Alternatively, just use a normal list that you append the individual values to:
def ash(list):
items_with_indices = []
for i,item in enumerate(list):
items_with_indices.append((item,i))
return items_with_indices
if __name__ == '__main__':
y = [1,2,3]
ys_with_indices = ash(y)
print ys_with_indices
def ash(lst):
return [(lst[x],x) for x in range(0,len(lst))]
You will get a list of tuples where the first value of the tuple is an element of the original list and the second the index of the element in the list.
For y = [1,2,3] the result is [(1, 0), (2, 1), (3, 2)]

Categories