Python - check if letter is displayed in a row
I have a task when I need to read an input and check that this input is happening in some words. For example:
Who are your friends? Fred Bill Sue Simone
What is the message? Should you make tea?
Sue could have written this.
He types: "Sue could have written this because the letters" S "," U "and" E "appear in every consecutive word. Another example:
Who are your friends? James Nicky Jake
What is the message? join and make enough cash today!
James could have written this.
Jake could have written this.
Both titles are printed because both of their letters appear sequentially in each word. I have the following code:
friends = input("Who are your friends? ").split()
message = input("What is the message? ").split()
name = []
other = []
for friend in friends:
for f in friend.lower():
for word in message:
print("checking if", f, "is in", word.lower())
if f in word.lower():
print("Adding", f, " to name list")
name.append(f)
break
else:
other.append(f)
continue
joinedResult = ''.join(name)
for person in friends:
if person.lower() in joinedResult:
print(person, "could have written this.")
It works perfect for the first example, but for the second example it prints all three names:
James could have written this.
Nicky could have written this.
Jake could have written this.
I found out that the code does not check if the letters in the name will be sequential , but checks if the name is any word. How can I solve this?
source to share
def find_char(string, char):
start_index = 0
while True:
yield string.lower().find(char, start_index) # checks for the char in the string
start_index += 1 # increments the index to find further in the word,
# eg:
# Bob constructed[index 0]
# ob constructed[index 1]
# b constructed[index 2]
def find_it(friends, message):
friends = friends.split()
for friend in friends:
sequence_check = []
for char in friend.lower():
gen = find_char(message, char) # creates the find_char generator
for _ in message: # limits the search to the length of the word
char_index = next(gen) # try to find the index
if char_index not in sequence_check: # if not in the sequence
sequence_check.append(char_index) # add it to it
break
if -1 in sequence_check: # this check if every character of the name is in the word
continue
if sorted(sequence_check) == sequence_check: # this part check if it in a sequence.
print (friend + ' could have written ' + message)
find_it('James Nicky Jake', "join and make enough cash today!")
find_it('Fred Bill Sue Simone', "Should you make tea?")
find_it("Bob", "Bob constructed Balloon Town")
Outputs:
James could have written join and make enough cash today!
Jake could have written join and make enough cash today!
Sue could have written Should you make tea?
Bob could have written Bob constructed Balloon Town
Rebuild it completely, now much cleaner.
Most of the work is done in the find_char function, which is a generator that has reduced the search space on each iteration, so it won't find Bob's place as [0,1,0], but [0,1, 2] in the sequence.
Any question feel free to ask.
source to share
You can do this using zip
and all()
:
friends = input("Who are your friends? ").split()
message = input("What is the message? ").lower().split()
for friend in friends:
if len(friend) <= len(message):
if all(x in y for x, y in zip(friend.lower(), message)):
print(friend, "could have written this.")
Demo:
>>>
Who are your friends? Fred Bill Sue Simone
What is the message? Should you make tea?
Sue could have written this.
>>>
Who are your friends? James Nicky Jake
What is the message? join and make enough cash today!
James could have written this.
Jake could have written this.
source to share
Using a regex expression might be a little easier:
friends = raw_input("Who are your friends? ").split()
message = raw_input("What is the message? ").lower()
name = []
other = []
for friend in friends:
regStr = '\w*\s?' + ''.join(['\w*' + f + '\w*\s' for f in friend.lower()])
if re.match(regStr, message):
name.append(friend)
for friend in name:
print friend + " could have written this."
The regex style like: \w*\s?(s)\w*\s\w*(u)\w*\s\w*(e)\w*
for a friendSue
TestCase:
Shoulde i?
[no match] ( sue found but not sequentially => [S]ho[u]ld[e] i?
)
Should I make tea?
[no matches]
Should u make tea?
[sue]
source to share
Note that you understand that the nth letter in their name must appear in the nth word in the message. Perhaps I am wrong on this and you can clarify.
You need to combine each letter in your name with a word from the message and then check for inclusion. You can do this usingzip
friends = 'James Nicky Jake'.split()
message = 'join and make enough cash today!'.split()
names = []
others = []
for friend in friends:
match = True
length = len(friend)
for letter, word in zip(friend.lower(), message):
if not letter in word.lower():
match = False
break
if match:
names.append(friend)
else:
others.append(friend)
for person in names:
print(person, "could have written this.")
source to share
friends=["James","Nicky","Jake"]
words=["James could have written this","Jake could have written this"]
for friend in friends:
for word in words:
for name in word.split():
if friend.lower()==name.lower():
print friend,"yes"
else:
print friend,"no"
You can use this simple code rather than comparing letter
with letter
, which is also error prone, since letters can be anywhere in a string, not necessarily contiguous.
source to share
Code
def whosdoneit(names,message):
good_names = []
l_m = len(message)
for name in names:
if len(name) > l_m: continue
if all(c.lower() in word.lower() for c, word in zip(name, message)):
good_names.append(name)
return good_names
print whosdoneit('Fred Bill Sue Simone'.split(),
'Should you make tea?'.split())
print whosdoneit('James Nicky Jake'.split(),
'join and make enough cash today!'.split())
Output
['Sue'] ['James', 'Jake']
A comment
The function returns a list of good names, people who could write a para-acrostic containing their name, so
- we start to initialize the list with a null list
Next, we will note that the name cannot be more than the number of words in the message, it can meet the requirements, so to use it later,
- we calculate and store the length, in words of the message
Now
-
we iterate over the list
names
to check if it matches thename
rules-
if the name is too long, further processing
-
using
zip
, we build a list of pairs, characterc
inname
,word
inmessage
, and we build a list of gates using a list comprehension -
if
all
booleans are true (all
andany
are useful builtins!) then addname
to the listgood_names
-
-
returns a list of good names to the caller.
I've also included a few function calls that mimic the OP's examples.
Possibly the highly anticipated one-liner
s
for suspects ...
def s(n,m):return [g for l in [len(m)] for g in n if len(g)<=l and all([c.lower() in w.lower() for c,w in zip(g,m)])]
source to share