Python list slicing error - python

I am using this code: https://pastebin.com/mQkpxdeV
wordlist[overticker] = thesentence[0:spaces]
in this function:
def mediumparser(inpdat3):
spaceswitch = 0
overticker = 0
thesentence = "this sentence is to count the spaces"
wordlist = []
while spaceswitch == 0:
spaces = thesentence.find(' ')
wordlist[overticker] = thesentence[0:spaces] # this is where we save the words at
thesentence = thesentence[spaces:len(thesentence)] # this is where we change the sentence for the
# next run-through
print('here2')
print(wordlist)
I can't figure out why it just keeps saying list index out of range.
The program seems to work but it gives an error, what am I doing wrong? I have looked through this book by Mark Lutz for an answer and I can't find one.

The "list index out of range" problem is never with list splicing, as shown in this simple test:
>>> l = []
>>> l[0:1200]
[]
>>> l[-400:1200]
[]
so the problem is with your left hand assignment wordlist[overticker] which uses a list access, not slicing, and which is subject to "list index out of range".
Just those 4 lines of your code are enough to find the issue
wordlist = []
while spaceswitch == 0:
spaces = thesentence.find(' ')
wordlist[overticker] = ...
wordlist is just empty. You have to extend/append the list (or use a dictionary if you want to dynamically create items according to a key)

Instead of doing wordlist[overticker] with wordlist being a empty list, you will need to use append instead, since indexing an empty list wouldn't make sense.
wordlist.append(thesentence[0:spaces])
Alternatively, you can pre-initiate the list with 20 empty strings.
wordlist = [""]*20
wordlist[overticker] = thesentence[0:spaces]
P.S.
wordlist[overticker] is called indexing, wordlist[1:10] is called slicing.

Related

I'm new to programming and am trying my hand at writing my own reverse function. Not going as planned [duplicate]

This question already has answers here:
How do you reverse the words in a string using python (manually)? [duplicate]
(4 answers)
Closed 5 years ago.
Below is a bit of code which seems to work at the start but populates my holding variable with half while leaving the other have in the list that I'm trying to give list elements from. The last element specifically. I don't know why this is not iterating through the entire flist. Help?
Thanks
Sembor
def reverse(text):
flist = []
holding = ""
for i in str(text):
flist.append(i)
print(flist)
for i in flist:
holding = holding + flist[-1]
del flist[-1]
print(holding)
print(flist)
reverse("JamesBond")
Instead of trying to modify your list while iterating over it. Instead, what you should do, is simply create a new string, and append the letters in the reverse order. You can do this by counting backwards using range:
def reverse(text):
reverse_string = ""
for i in range(len(text) - 1, -1, -1):
reverse_string += text[i]
print(reverse_string)
reverse("JamesBond")
However, the best way to do this in python, is by making use of slicing, in which, you can simply do:
reverse_string = text[::-1]
As this comment says, the problem is that you're modifying the list as you're iterating over it.
Basically, for i in range plist isn't going through all the elements since you making the list shorter as you loop through it. This is what's happening to your list as you're iterating it.
holding plist
d ["J","a","m","e","s","B","o","n","d"]
^
dn ["J","a","m","e","s","B","o","n"]
^
dno ["J","a","m","e","s","B","o"]
^
dnoB ["J","a","m","e","s","B"]
^
dnoBs ["J","a","m","e","s"]
^ #can't loop any further
What you can do instead is something like this
for i in range(len(plist), -1, -1):
holding = holding + plist[i]
Or this
def reverse(text):
return text[::-1]
Or you could use the built in reversed function, like equaio did.
When creating lists from strings you can use list.comprehension:
[i for i in text]
And you could reverse this by using enumerate for instance:
[text[-ind-1] for ind, i in enumerate(text)]
as I understand you want to take the string "JamesBond" and reverse it to "dnoBsemaJ". I am also extremely new to Python. I gave your function a try and came up with the following. It may not be the prettiest but it does reverse the text.
def reverse(_string):
_stringLen = len(_string)
i = _stringLen - 1
_newstring = ""
while i >= 0:
_newstring = _newstring + _string[i]
i -= 1
return _newstring
print reverse("JamesBond")
Prints out : dnoBsemaJ
Splicing can help you unless you do want to write the algorithm to reverse
>>> k = 'JamesBond'
>>> rev_str = k[::-1]
>>> rev_str
'dnoBsemaJ'
>>> type(rev_str)
<type 'str'>

How to reference the next item in a list in Python?

I'm fairly new to Python, and am trying to put together a Markov chain generator. The bit that's giving me problems is focused on adding each word in a list to a dictionary, associated with the word immediately following.
def trainMarkovChain():
"""Trains the Markov chain on the list of words, returning a dictionary."""
words = wordList()
Markov_dict = dict()
for i in words:
if i in Markov_dict:
Markov_dict[i].append(words.index(i+1))
else:
Markov_dict[i] = [words.index(i+1)]
print Markov_dict
wordList() is a previous function that turns a text file into a list of words. Just what it sounds like. I'm getting an error saying that I can't concatenate strings and integers, referring to words.index(i+1), but if that's not how to refer to the next item then how is it done?
You can also do it as:
for a,b in zip(words, words[1:]):
This will assign a as an element in the list and b as the next element.
The following code, simplified a bit, should produce what you require. I'll elaborate more if something needs explaining.
words = 'Trains the Markov chain on the list of words, returning a dictionary'.split()
chain = {}
for i, word in enumerate(words):
# ensure there's a record
next_words = chain.setdefault(word, [])
# break on the last word
if i + 1 == len(words):
break
# append the next word
next_words.append(words[i + 1])
print(words)
print(chain)
assert len(chain) == 11
assert chain['the'] == ['Markov', 'list']
assert chain['dictionary'] == []
def markov_chain(list):
markov = {}
for index, i in enumerate(list):
if index<len(list)-1:
markov[i]=list[index+1]
return (markov)
The code above takes a list as an input and returns the corresponding markov chain as a dictionary.
You can use loops to get that, but it's actually a waste to have to put the rest of your code in a loop when you only need the next element.
There are two nice options to avoid this:
Option 1 - if you know the next index, just call it:
my_list[my_index]
Although most of the times you won't know the index, but still you might want to avoid the for loop.
Option 2 - use iterators
& check this tutorial
my_iterator = iter(my_list)
next(my_iterator) # no loop required

Python number to word converter needs a space detector

I have been working on a sort of encryption tool in python. This bit of code is for the decryption feature.
The point is to take the given numbers and insert them into a list from where they will be divided by the given keys.
My idea for code is below but I keep getting the out of list index range whenever I try it out. Any suggestions? Keep in mind I'm a beginner:
need = []
detr = raw_input('What would you like decrypted?')
count = 0
for d in detr:
if (d == '.' or d == '!') or (d.isalpha() or d== " "):
count +=1
else:
need[count].append(d)
The problem is you are attempting to overwrite list values that don't exist.
list.append(item) adds item to the end of list. list[index] = item inserts item into list at position index.
list = [0,0,0]
list.append(0) # = [0,0,0,0]
list[0] = 1 # [1,0,0,0]
list[99] = 1 # ERROR: out of list index range
You should get rid of the count variable entirely. You could append None in the case of d==' ' etc. or just ignore them.
The way I understood your description you want to extract the numbers in a string and append them to a list using a for-loop to iterate over each character.
I think it would be easier doing it with regular expressions (something like r'([\d]+)').
But the way joconner said: "get rid of the count variable":
need = []
detr = input('What would you like decrypted?\n')
i = iter(detr) # get an iterator
# iterate over the input-string
for d in i:
numberstr = ""
try:
# as long as there are digits
while d.isdigit():
# append them to a cache-string
numberstr+= d
d = next(i)
except StopIteration:
# occurs when there are no more characters in detr
pass
if numberstr != "":
# convert the cache-string to an int
# and append the int to the need-array
need.append( int(numberstr) )
# print the need-array to see what is inside
print(need)

Why can't I append a char to an empty list in Python?

In a program I am writing to create a list of words from a list of chars, I am getting a "list index out of range" exception.
def getlist(filename):
f = open('alice.txt','r')
charlist = f.read()
wordlist = []
done = False
while(not done):
j = 0
for i in range(0,len(charlist)):
if charlist[i] != ' ' and charlist[i] != '\n':
wordlist[j] += charlist[i]
else: j+= 1
done = i == len(charlist)-1
return wordlist
So I started playing around with how lists work, and found that:
list = ['cars']
list[0]+= '!'
gives list = ['cars!']
However, with:
list = []
list[0]+= '!'
I get an out of bounds error. Why doesn't it do what seems logical: list= ['!']? How can I solve this? If I must initialize with something, how will I know the required size of the list? Are there any better, more conventional, ways to do what I'm attempting?
['cars'] is a list containing one element. That element is the string 'cars', which contains 4 characters.
list[0] += '!' actually does 3 separate things. The list[0] part selects the element of list at position 0. The += part both concatenates the two strings (like 'cars' + '!' would), and stores the resulting string back in the 0th slot of list.
When you try to apply that to the empty list, it fails at the "selects the element at position 0" part, because there is no such element. You are expecting it to behave as if you had not the empty list, but rather ['']; the list containing one element which is the empty string. You can easily append ! onto the end of an empty string, but in your example you don't have an empty string.
To add to a list, including an an empty one, use the append() method:
>>> mylist = []
>>> mylist.append('!')
>>> mylist
['!']
However, with:
list = []
list[0]+= '!'
I get an out of bounds error. Why doesn't it do what seems logical:
list= ['!']?
Because that isn't logical in Python. To append '!' to list[0], list[0] has to exist in the first place. It will not magically turn into an empty string for you to concatenate the exclamation mark to. In the general case, Python would not have a way to figure out what kind of "empty" element to magic up, anyway.
The append method is provided on lists in order to append an element to the list. However, what you're doing is massively over-complicating things. If all you want is a list consisting of the words in the file, that is as easy as:
def getlist(filename):
with open(filename) as f:
return f.read().split()
Your error is not from the statement list[0]+= '!', its from accessing an empty list which is out of range error :
>>> my_list = list()
>>> my_list[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>>
And += is not used for appending in a list, its for concatenating a string or numeric addition and internally its calling the following method.
__iadd__(...)
x.__iadd__(y) <==> x+=y

Reading and Grouping a List of Data in Python

I have been struggling with managing some data. I have data that I have turned into a list of lists each basic sublist has a structure like the following
<1x>begins
<2x>value-1
<3x>value-2
<4x>value-3
some indeterminate number of other values
<1y>next observation begins
<2y>value-1
<3y>value-2
<4y>value-3
some indeterminate number of other values
this continues for an indeterminate number of times in each sublist
EDIT I need to get all the occurrences of <2,<3 & <4 separated out and grouped together I am creating a new list of lists [[<2x>value-1,<3x>value-2, <4x>value-3], [<2y>value-1, <3y>value-2, <4y>value-3]]
EDIT all of the lines that follow <4x> and <4y> (and for that matter <4anyalpha> have the same type of coding and I don't know a-priori how high the numbers can go-just think of these as sgml tags that are not closed I used numbers because my fingers were hurting from all the coding I have been doing today.
The solution I have come up with finally is not very pretty
listINeed=[]
for sublist in biglist:
for line in sublist:
if '<2' in line:
var2=line
if '<3' in line:
var3=line
if '<4' in line:
var4=line
templist=[]
templist.append(var2)
templist.append(var3)
templist.append(var4)
listIneed.append(templist)
templist=[]
var4=var2=var3=''
I have looked at ways to try to clean this up but have not been successful. This works fine I just saw this as another opportunity to learn more about python because I would think that this should be processable by a one line function.
itertools.groupby() can get you by.
itertools.groupby(biglist, operator.itemgetter(2))
If you want to pick out the second, third, and fourth elements of each sublist, this should work:
listINeed = [sublist[1:4] for sublist in biglist]
You're off to a good start by noticing that your original solution may work but lacks elegance.
You should parse the string in a loop, creating a new variable for each line.
Here's some sample code:
import re
s = """<1x>begins
<2x>value-1
<3x>value-2
<4x>value-3
some indeterminate number of other values
<1y>next observation begins
<2y>value-1
<3y>value-2
<4y>value-3"""
firstMatch = re.compile('^\<1x')
numMatch = re.compile('^\<(\d+)')
listIneed = []
templist = None
for line in s.split():
if firstMatch.match(line):
if templist is not None:
listIneed.append(templist)
templist = [line]
elif numMatch.match(line):
#print 'The matching number is %s' % numMatch.match(line).groups(1)
templist.append(line)
if templist is not None: listIneed.append(templist)
print listIneed
If I've understood your question correctly:
import re
def getlines(ori):
matches = re.finditer(r'(<([1-4])[a-zA-Z]>.*)', ori)
mainlist = []
sublist = []
for sr in matches:
if int(sr.groups()[1]) == 1:
if sublist != []:
mainlist.append(sublist)
sublist = []
else:
sublist.append(sr.groups()[0])
else:
mainlist.append(sublist)
return mainlist
...would do the job for you, if you felt like using regular expressions.
The version below would break all of the data down into sublists (not just the first four in each grouping) which might be more useful depending what else you need to do to the data. Use David's listINeed = [sublist[1:4] for sublist in biglist] to get the first four results from each list for the specific task above.
import re
def getlines(ori):
matches = re.finditer(r'(<(\d*)[a-zA-Z]>.*)', ori)
mainlist = []
sublist = []
for sr in matches:
if int(sr.groups()[1]) == 1:
print "1 found!"
if sublist != []:
mainlist.append(sublist)
sublist = []
else:
sublist.append(sr.groups()[0])
else:
mainlist.append(sublist)
return mainlist

Categories