High Scores! From ACM 2017 - python

testcases = int(input())
for i in range(testcases):
n = int(input())
names = []
for a in range(n):
names.append(input())
prefix = ''
for b in range(len(names[0])):
for c in names:
if c.startswith(prefix) == True:
common = True
else: common = False
if common == False:
break
prefix += names[0][b]
print(prefix)
I am given a list of names and I need to find the common prefix that applies to every name. My program works, but always returns one more letter than is supposed to be there. Why is this, and how do I fix it?

If the current prefix matches all the entered names, you add one more character to it. When it fails to match, you break out of the loop - but the character that caused the failure is still attached to the end of prefix.
There are various ways to fix this, but one possibility is to just remove the last character by adding this statement outside the loop:
prefix = prefix[:-1] # python slice notation - remove the last element
There are some style issues with your code. Those would be best addressed on CodeReview rather than Stackoverflow.
I would have done it this way (after replacing your input statements with a hard-coded test case):
x = ["Joseph", "Jose", "Josie", "Joselyn"]
n = 0
try:
while all(a[n] == x[0][n] for a in x[1:]):
n += 1
except IndexError:
pass
print(x[0][:n])
This script prints "Jos".

Related

SNHU Python 'Simon Says': compare two strings for equality character-wise, without using an index?

I was given a prompt to solve and was able to write code that passed, but my question is, is there a more simplified way I could write this without having to create a new named variable (s_index = 0)? The code works just fine but I'm not sure if I solved it the way I was expected to and am open to suggestions for improvement :)
Please note that this section in the work book has us focusing on using continue and break within loops
"Simon Says" is a memory game where "Simon" outputs a sequence of 10 characters (R, G, B, Y)
and the user must repeat the sequence. Create a for loop that compares the two strings.
For each match, add one point to user_score. Upon a mismatch, end the game.
Sample output with inputs: 'RRGBRYYBGY' 'RRGBBRYBGY'
User score: 4
user_score = 0
simon_pattern = input()
user_pattern = input()
s_index = 0
for letter in user_pattern:
if letter == simon_pattern[s_index]:
user_score += 1
s_index += 1
else:
break
print('User score:', user_score)
using functions to encapsulate small specific parts of your logic is often helpful
def do_score(user_pattern="1234",simon_pattern="1235"):
# using enumerate you can get the indices
for s_index,a_char in enumerate(simon_pattern):
if s_index >= len(user_pattern) or a_char != user_pattern[s_index]:
# the index should always match the "sum" so no need to track or compute the sum
return s_index
return len(simon_pattern)
this method takes 2 strings and "scores" them based on the "simon_pattern" returning the score
then just
print(do_score(user_entered_input,simon_pattern))
I will rewrite this to this way: (this way you can completely eliminate the variable index, and simon_pattern[index] to get the letter)
Note - in Python a word is just a sequence of character/letters, you can iterate it directly, no need to use index.
simon = 'RRGBRYYBGY'
user = 'RRGBBRYBGY' # User score: 4
user_score = 0
for user_char, simon_char in zip(user, simon):
if user_char == simon_char: # continue to check/and match...
user_score += 1
else: # break, if no match!
break
print('User score:', user_score)
Strictly, you never need to know the index or index into the strings, you can just use zip() to combine tuples of respective characters from the two (possibly different-length) strings:
def do_score(user_pattern='RRGBRYYBGY', simon_pattern='RRGBBRYBGY'):
score = 0
for uc,sc in zip(user_pattern, simon_pattern):
if uc == sc:
score += 1
else:
break
return score
assert do_score('', '') == 0
assert do_score('RRG', '') == 0
assert do_score('', 'RRG') == 0
assert do_score('RRG', 'RRGB') == 3

Skipping iterations in a for loop when working with strings (in Python)

I'm trying to write a program that works with a string as input (a sentence or word). With a for loop, I iterate through each character in turn. When I come across the letter p, the program should skip a couple of iterations. I have found a lot of tips regarding skipping iterations when working with integers. However, in my code, I'm working with strings. Does anyone have any helpful tips for this? Thanks in advance!
Here is an adapted piece of my code (what I have so far):
language_input = input()
for character in language_input:
if character == "p":
# Now, I have to skip a few iterations (e.g. skip 3 characters)
It rather depends on what you need to do with the characters in your string. Here's an idea:
language_input = input()
i = 0
while i < len(language_input):
if language_input[i] == 'p':
i += 3
else:
i += 1
# do something else
You can use an extra variable and do nothing if it is set
language_input = input()
check = 0
for character in language_input:
if check:
check -= 1
continue
if character == "p":
check = 3 #set to number of iterations you want to skip
You could use an iterator:
language_input = 'abcdefghij'
s = iter(language_input)
while True:
try:
character = next(s)
if character == 'd':
print('…', end='')
next(s)
next(s)
next(s)
print(character, end='')
except StopIteration:
break
output: abc…dhij
To be more efficient in skipping many items, you could use itertools.islice:
from itertools import islice
# … only showing changed part of code
if character == 'd':
print('…', end='')
list(islice(s, 3)) # get 3 elements at once
# …

Failing when tested with 90 test cases

I am making a simple program to check if a UID is valid or not:
It must contain at 2 least uppercase English alphabet characters.
It must contain at 3 least digits (0-9).
It should only contain alphanumeric characters (a-z, A-Z & 0-9).
No character should repeat.
There must be exactly 10 characters in a valid UID.
This is the code I'm using:
if __name__ == '__main__':
n = int(input())
values = [str(input()) for q in range(1,n+1)]
def checker():
cap_count = 0
num_count = 0
alnm_count = 0
for x in values[:]:
for p in x:
if p.isupper():
cap_count = cap_count+1
if cap_count > 1 and p.isnumeric():
num_count = num_count+1
if (len(x) == 10) and (x.isalnum()) and (len(x) == len(set(x))) and (cap_count > 1) and (num_count > 2):
print("Valid")
else:
print("Invalid")
checker()
Sample Input:
2
B1CD102354
B1CDEF2354
So, on giving these inputs, it works well. I have tried it up to 6-7 inputs and it works.
There is no error, it's just not giving the answer on one test case with 90 values.
Here is a link to the test that I am attempting
There's no reason that the numeric test is dependent on the uppercase test.
Change:
if cap_count > 1 and p.isnumeric():
to:
if p.isnumeric():
Also, the counters should be reset for every new value, so move the counter initialization inside the loop:
for x in values[:]:
cap_count = 0
num_count = 0
...
This seems to be the Hackerrank problem
Following code for conditions works.
def checker(uid):
if len(uid) != 10: return False
if not uid.isalnum(): return False
if len(uid) != len(set(uid)): return False
if len([c for c in uid if c.isdigit()]) < 3: return False
if len([c for c in uid if c.isupper()]) < 2: return False
return True
if __name__ == '__main__':
n = int(input())
for _ in range(n):
if checker(input()):
print("Valid")
else:
print("Invalid")
This is the offending line:
if cap_count > 1 and p.isnumeric():
which is actually adding an unwanted constraint, i.e. making digits acceptable only if at least 2 capitals were found.
By the way, this is the sort of data validation that regex is designed for, meaning that you can do all those checks in a couple of lines:
import re
pattern = r"^(?=(?:[a-z\d]*[A-Z]){2})(?=(?:\D*\d){3})(?:([a-zA-Z\d])(?!.*\1)){10}$"
regex = re.compile(pattern)
if regex.match("uid_here"):
do_something
I strongly suggest you delve into re documentation (especially the howto section) if you're willing to dissect that weird pattern and know exactly what it does.
But for the sake of summarizing a TL;DR, each element of the pattern defines a specific rule that the string must comply with to match the pattern, i.e:
^ and $ represent the ends of the string
(?=(?:[a-z\d]*[A-Z]){2}) this makes sure that at least 2 capitals are found
(?=(?:\D*\d){3}) this makes sure that at least 3 digits are found
(?:([a-zA-Z\d])(?!.*\1)){10} this makes sure that the string has exactly 10 characters with no repetition allowed
The second condition seems to accept digits only if at least two upper case letters were found before. In other words, digits appearing before the second upper case letter are not counted. It's due to the cap_count > 1 term in the condition.
In the example "123ABCDEFG" from my comment above, all digits appear before all letters, so the digit counter remains zero and the final test (num_count > 2) fails.

Checks for a Path in a List of Strings Given a Starting and Ending Point

We are tasked to create a program that will check if there is a possible way of going from a starting string to an end string, given a list of strings with the same length. There is a catch, we can only go from the current string to the adjacent string if both strings only have one character that is different. If there is no possible path from the starting string to the end string, just print not possible but if there is, output the number of steps from the start to end.
Example:
li = ["booster", "rooster", "roaster", "coaster", "coasted"]
start = "roaster"
end = "booster"
Output: 3
li = ["booster", "rooster", "roaster", "coastal", "coasted"]
start = "roaster"
end = "coasted"
Output: none
I made an approach which manually checks if adjacent strings only have 1 character differences and returns the result based on these differences. Kinda slow if you ask me, given that the length of the list could be at most 100. Can you demonstrate a faster approach?
def checker(str1, str2, change = 0):
for index, character in enumerate(str1): # Traverses the whole
if character != str2[index]: # string and checks for
change+=1 # character differences
return True if change == 1 else False # Only 1 character is different
li = ["booster", "rooster", "roaster", "coaster", "coasted"]
m = len(li)
for j in range(m): li.append(input())
start, end = input().split()
if end in li: endI = li.index(end) # Gets end string index in the list
else:
print("not possible")
break
if start in li: startI = li.index(start) # Gets start string index in the list
else:
print("not possible")
break
if startI < endI: # If start string comes first before
# the end string, keep incrementing.
while li[startI] != end and startI < m-1:
if not checker(li[startI], li[startI+1]):
print("not possible")
break
startI += 1
print(abs(startI-(li.index(start)+1)))
else: # Otherwise, keep decrementing.
while li[startI] != end and startI > 0:
if not checker(li[startI], li[startI-1]):
print("not possible")
break
startI -= 1
print(abs(startI-(li.index(start)+1)))
If my approach is the fastest (which I highly doubt), I want to know if there are loopholes in my approach. Assume that the start and end strings can also be absent in the list given. Just print not possible if they are not in the list.
I hope that looks better:
import regex
def word_path(words, start, end):
if end in words and start in words:
endI = words.index(end)
startI = words.index(start)
else:
return "not possible"
step = 1 if startI <= endI else -1
for index in range(startI, endI, step):
if not regex.match("(%s){e<=1}" %li[index], li[index + step]):
return "not possible"
return abs(startI - endI) + 1
li = ["booster", "rooster", "roaster", "coastal", "coasted"]
start, end = input().split()
print(word_path(li, start, end))
It is supposed to be regex. Regex provides additional regular expression features, e.g. it makes it possible to check for a number of errors {e<=1}. The re- module doesn't provide these features. I guess that is the reason for the wrong result. You may need to install the regex-module with pip install regex first, but then it should work:
regex_module

how can i fix the syntax error in the file name or its path?

when I run that code it comes out to me this error:
IndexError: string index out of range
I have no idea why I comes out to me this error and I don't have
any note but if you want to ask me about any thing don't hesitate
letters_string = "d g o"
letters_list = []
# Check Space
def convert_letters_to_list(word):
"""
This Function takes the letters from the users
and checks if users put more than one space
between letters if True It Removes The extra Spaces
"""
if word[0].isspace() == True:
convert_letters_to_list(word[1])
elif word[0].isalpha() == True:
letters_list.append((word[0])) + convert_letters_to_list(word[1:])
else:
convert_letters_to_list(word[1:])
convert_letters_to_list(letters_string)
print(letters_list)
You function is recursive so after a while, any letter index past 0 will be out of the original string.
Here is a fixed version of your code.
letters_string = "d g o"
letters_list = []
# Check Space
def convert_letters_to_list(word):
"""
This Function takes the letters from the users
and checks if users put more than one space
between letters if True It Removes The extra Spaces
"""
if word[0].isalpha() == True or (word[0].isspace() and not letters_list[-1].isspace()):
letters_list.append((word[0]))
if len(word) == 1:
return
convert_letters_to_list(word[1:])
convert_letters_to_list(letters_string)
print(letters_list)

Categories