String index out of range, solution is working fine - python

I'm trying to change all the characters to the symbol "#" except the last 4. The error I get:
> Traceback (most recent call last):
File "tests.py", line 16, in
> <module>
> r = maskify(cc) File "/workspace/default/solution.py", line 19, in maskify
> n[i] = c[i] IndexError: string index out of range
The code
c = "3656013700"
cc = list(c)
a = (len(cc)-1) - 4
b = []
def maskify(cc):
n = list(len(cc) * "#")
while len(cc) <= 4:
return str(cc)
break
else:
for i in range(len(cc)):
if i <= a:
n[i] = n[i]
else:
n[i] = c[i]
b = "".join([str(i) for i in n])
return b
maskify(cc)

I don't know why you're complicating it. As #blorgon has already pointed it out, you can directly return it in one line. Further simplifying it, you don't need even need to convert the string into a list. Just directly pass the string as argument.
c = "3656013700"
def maskify(c):
return (len(c) - 4) * "#" + c[-4:]
print(maskify(c))
If this is not what you're trying to achieve, your question is unclear.

You are going through a complicated route. Here is another approach:
c = "3656013700"
def maskify(cc):
return cc.replace(cc[:-4], '#'*(len(cc)-4))
print (maskify(c))
Output:
######3700

If you want to go with the iterative approach you can simplify the code substantially:
def maskify(c):
# Check if lenght of string is 4 or less
if len(c) <= 4:
return c
else:
# string into a list
cc = list(c)
# Iterate over the list - 4 last items
for i in range(len(c)-4):
cc[i] = "#"
return "".join(cc)
s = "3656013700"
s = maskify(s)
print(s)

Related

Python Index error using generator with yield

I'm running this code and I get the values I want from it, but there is also an IndexError: tuple index out of range for lines 12 and 18
import statistics as st
def squares(*args):
i = 0
val = []
fin = []
val = args
while True:
avg = (st.mean(val))
fin = (avg - val[i]) ** 2 # line 12
yield fin
i += 1
mylist = squares(3, 4, 5)
for x in mylist: # line 18
print(x)
result:
1
0
1
Traceback (most recent call last):
File line 18, in <module>
for x in mylist:
File line 12, in squares
fin = (avg - val[i]) ** 2
IndexError: tuple index out of range
Base on your code there are some variables & methods that you did that I think you can also change. Like example on this one. I commented out your old code so you can see the changes & difference.
import statistics as st
def squares(*args):
#i = 0
#val = []
fin = []
val = args
for n in val:
avg = (st.mean(val))
fin = (avg - n) ** 2 # line 12, #val[i]
#i += 1
yield fin
mylist = squares(3, 4, 5)
for x in mylist: # line 18
print(x)
I can see here that you are trying to access every value of val with fin = (avg - val[i]) ** But you can also use a for loop with it & don't need for a i variable as index. Also what #schwobaseggl is correct, you get the error IndexError: tuple index out of range because you kept incrementing or adding up your i to the point where you are trying to access a value from your val variable that is beyond its length.
You can simplify the generator function:
import statistics as st
def squares(*args):
avg = st.mean(args)
for arg in args:
yield (avg - arg) ** 2
Note that in your original, you have an infinite loop (while True) that you never break and that keeps incrementing index i while the i-accessed sequence val does not grow. That was always an IndexError waiting to happen.

"Unsupported operand type for +: NoneType" when trying to append a character to a string

I am trying to solve the following question:
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
string convert(string s, int numRows);
I have written the following code but I am getting error in the bold line
" TypeError: unsupported operand type(s) for +: 'NoneType' and 'unicode'"
class Solution(object):
def convert(self, s, numRows):
"""
:type s: str
:type numRows: int
:rtype: str
"""
if numRows==1:
return s
templist=[None]*numRows
ret=" "
curRow=0
goingDown=0
for each_char in s:
if templist[curRow]:
templist[curRow]=each_char
else:
**templist[curRow]=templist[curRow] + each_char**
if (curRow==numRow-1 or curRow == 0):
goingDown = not goingDown
if goingDown:
curRow=curRow+1
else:
curRow=curRow-1
for each_str in templist:
ret=ret+each_str
print ret
Am I doing something wrong in this. It will be great if someone can point out the problem here.
Thanks in advance
Your conditions seem to be reversed in the following lines:
if templist[curRow]:
templist[curRow]=each_char
else:
**templist[curRow]=templist[curRow] + each_char**
It should probably read:
if templist[curRow]:
templist[curRow]=templist[curRow] + each_char
else:
templist[curRow]=each_char
This ensures that it only appends to the string in templist[curRow] if that string already exists (is not None), and so avoids the error of adding a string to None.
A better way might be to set templist = [""] * numRows, i.e. a list of empty strings, then just add to it using templist[curRow] += each_char, which will always work because you can add a character to an empty string.
Yes, you're doing something wrong.
The line templist=[None]*numRows makes your templist variable hold a bunch of Nones. You then proceed to take one of those Nones, and try to "add" one of them to a string with the statement that you have in bold: templist[curRow]=templist[curRow] + each_char (i.e. the righthand side of this assignment evaluates to None + each_char).
You can't add a string and a None in Python, hence the error.
string = 'PAHNAPLSIIGYIR'
string = list(string)
rows = []
def make_output(string, num_rows):
i = 0
while i < num_rows:
if i%2 == 0:
a = []
while len(a) < 4:
if len(string)==0:
break
a.append(string.pop(0))
rows.append(a)
if i%2 != 0:
a = []
while len(a) < 7:
a.append(string.pop(0))
rows.append(a)
i += 1
for i in range(len(rows)):
if i%2 == 0:
print(' '.join(rows[i]))
if i%2 != 0:
print(' '.join(rows[i]))
make_output(string, 3)
You can use a function like this, where you designate lengths for even and odd rows, then you can pop from your string. Then you can just print even and odd rows with proper spacing.
(xenial)vash#localhost:~/python/AtBS$ python3.7 solve.py
P A H N
A P L S I I G
Y I R
(xenial)vash#localhost:~/python/AtBS$ python3.7 solve.py
M M * H
Y A E S V S *
N I A

Kindly help me debug this python program, with list iteration error

Question :
To find the percentage of 2 sentences matching.
If 100%, Print "Exact Match!"
Ignore the difference of 1 character between any 2 words being checked. (1 character error margin)
Program :
from difflib import SequenceMatcher
def difWord(s1, s2):
m = len(s1)
n = len(s2)
if abs(m - n) > 1:
return false
count = 0
correct = 0
i = 0
j = 0
while i < m and j < n:
if s1[i] != s2[j]:
count+=1
if count==1:
return true
def seqMatch(a,b):
rat = SequenceMatcher(None,a,b).ratio()
if rat==1 :
print("Exact Match!")
else :
print(rat*100)
splitted1 = a.split()
splitted2 = b.split()
c=0
for x,y in splitted1.iteritems(),splitted2.iteritems() :
if difWord(x,y) :
c+=1;
per = (count*100)/4
print(per)
if __name__ == "__main__":
a = "He is a boy"
b = "She is a girl"
c = "He is a boy"
seqMatch(a,b)
Error :
Traceback (most recent call last):
File "C:\Users\eidmash\Documents\Demo-Project\Day0.py", line 59, in <module>
seqMatch(a,c)
File "C:\Users\eidmash\Documents\Demo-Project\Day0.py", line 43, in seqMatch
for x,y in splitted1.iteritems(),splitted2.iteritems() :
AttributeError: 'list' object has no attribute 'iteritems'
According to your traceback, the error is in the line:
for x,y in splitted1.iteritems(),splitted2.iteritems():
The method str.split() returns a list, thus it isn't a dictionary that would provide the iteritems function. However you can just iterate through the two list at a time with the help of the zip function. Modify that line to:
for x, y in zip(splitted1, splitted2):
Otherwise, without the use of that zip function to bundle the items of the two lists together, Python will interpret that as iterating through the two items which happen to be the two lists, yielding them for use in the for loop (actually will cause an error if the lists themselves don't have exactly two items as they will be unpacked into x and y), which is not what you want.
try
for x,y in zip(splitted1,splitted2)

Recoding of binary file

I have a file that has this contents
1 5 9 14 15
00000
10000
00010
11010
00010
I want to parse the file so that the following is output
UUUUUUUUUUUUUU
YUUUUUUUUUUUUU
UUUUUUUUUUUUYY
YUUUYUUUUUUUYU
UUUUUUUUUUUUYU
This means the first row provides a position. If there is a 0, it becomes U. If it is a 1 it becomes Y. Between the first two columns there are 4 unmapped cols which means that for these four cols all rows are U - and 0
I tried the following in python
#!/usr/bin/env python2
import sys
with open(sys.argv[1]) as f:
f.readline()
for line in f:
new = ''
for char in line.rstrip():
if char == '0':
new += 'UU'
elif char == '1':
new +='YU'
print new.rstrip()[:-1]
The problem is that this script only works if the positions are 2 apart but they can also be larger - how can I extend the script?
there is some poroblem when i run the code from, Delimity - get an error
dropbox.com/s/cf8rbv20bgyvssq/conv_inp?dl=0
these are the real da
Traceback (most recent call last):
File "./con.py", line 8, in <module>
for v in xrange(max(positions) + 1):
OverflowError: long int too large to convert to int
Just a guess.
Implement the converter:
def convert(s):
return "UUU".join({"0": "U", "1": "Y"}[c] for c in s[:-1]) + "U"
And test it:
assert convert("00000") == "UUUUUUUUUUUUUU"
assert convert("10000") == "YUUUUUUUUUUUUU"
assert convert("00010") == "UUUUUUUUUUUUYU"
assert convert("11010") == "YUUUYUUUUUUUYU"
assert convert("00010") == "UUUUUUUUUUUUYU"
Check this code:
#!/usr/bin/env python2
import sys
def myxrange(to):
x = 0
while x < to:
yield x
x += 1
with open(sys.argv[1]) as f:
positions = map(lambda x: long(x) - 1, f.readline().split())
max_pos = max(positions)
for line in f:
new = ''
for i in myxrange(max_pos + 1):
if i in positions and line[positions.index(i)] == '1':
new += 'Y'
else:
new += 'U'
print new.rstrip()

get nth line of string in python

How can you get the nth line of a string in Python 3?
For example
getline("line1\nline2\nline3",3)
Is there any way to do this using stdlib/builtin functions?
I prefer a solution in Python 3, but Python 2 is also fine.
Try the following:
s = "line1\nline2\nline3"
print s.splitlines()[2]
a functional approach
>>> import StringIO
>>> from itertools import islice
>>> s = "line1\nline2\nline3"
>>> gen = StringIO.StringIO(s)
>>> print next(islice(gen, 2, 3))
line3
`my_string.strip().split("\n")[-1]`
Use a string buffer:
import io
def getLine(data, line_no):
buffer = io.StringIO(data)
for i in range(line_no - 1):
try:
next(buffer)
except StopIteration:
return '' #Reached EOF
try:
return next(buffer)
except StopIteration:
return '' #Reached EOF
A more efficient solution than splitting the string would be to iterate over its characters, finding the positions of the Nth and the (N - 1)th occurence of '\n' (taking into account the edge case at the start of the string). The Nth line is the substring between those positions.
Here's a messy piece of code to demonstrate it (line number is 1 indexed):
def getLine(data, line_no):
n = 0
lastPos = -1
for i in range(0, len(data) - 1):
if data[i] == "\n":
n = n + 1
if n == line_no:
return data[lastPos + 1:i]
else:
lastPos = i;
if(n == line_no - 1):
return data[lastPos + 1:]
return "" # end of string
This is also more efficient than the solution which builds up the string one character at a time.
From the comments it seems as if this string is very large.
If there is too much data to comfortably fit into memory one approach is to process the data from the file line-by-line with this:
N = ...
with open('data.txt') as inf:
for count, line in enumerate(inf, 1):
if count == N: #search for the N'th line
print line
Using enumerate() gives you the index and the value of object you are iterating over and you can specify a starting value, so I used 1 (instead of the default value of 0)
The advantage of using with is that it automatically closes the file for you when you are done or if you encounter an exception.
Since you brought up the point of memory efficiency, is this any better:
s = "line1\nline2\nline3"
# number of the line you want
line_number = 2
i = 0
line = ''
for c in s:
if i > line_number:
break
else:
if i == line_number-1 and c != '\n':
line += c
elif c == '\n':
i += 1
Wrote into two functions for readability
string = "foo\nbar\nbaz\nfubar\nsnafu\n"
def iterlines(string):
word = ""
for letter in string:
if letter == '\n':
yield word
word = ""
continue
word += letter
def getline(string, line_number):
for index, word in enumerate(iterlines(string),1):
if index == line_number:
#print(word)
return word
print(getline(string, 4))
My solution (effecient and compact):
def getLine(data, line_no):
index = -1
for _ in range(line_no):index = data.index('\n',index+1)
return data[index+1:data.index('\n',index+1)]

Categories