Python Itertools Code Optimisation - python

Given question (the contest is now over)
a password consists of exactly n lowercase English letters.
the password is melodious, meaning that consonants can only be next to
vowels and vowels can only be next to consonants. Example: bawahaha
the password cannot contain the letter y (because it's both a
consonant and vowel).
the first letter of the password can be either
a vowel or consonant.
Given the length, n, of the password,
print all of the possible passwords that meet the conditions above.
Input Format
The line of input contains the integer (the length of the password).
Constraints
Output Format
Print each of the possible passwords, one per line. The order of the passwords does not matter.
My Code in Python:
import sys
import itertools
n = int(raw_input().strip())
consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'z']
vowels = ['a', 'e', 'i', 'o', 'u']
test4 = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'z', 'a', 'e', 'i', 'o', 'u']
answer = set(itertools.product(test4, repeat=n))
for letters in answer:
for j in xrange(len(letters)):
flag = 1
if j != len(letters) - 1:
if letters[j] in vowels and letters[j+1] in vowels:
flag = 0
break
if letters[j] in consonants and letters[j+1] in consonants:
flag = 0
break
if flag:
for j in letters:
sys.stdout.write(j)
print ""
Is there a better way to do this?

Of course there's a better way (if you mean faster). You can generate a itertools.product where you don't have to "discard" items.
You can simply create a product of vowel, consonant, vowel, consonant, ... (alternating both lists n times) and one which starts with consonant, vowel, consonant, vowel, .... The returned items will always satisfy the condition so all that needs to be done is printing them.
import itertools
def alternating(seq1, seq2, length):
"""Generator that alternatingly yields seq1 and seq2, `length` times"""
assert length >= 0
for _ in range(length // 2):
yield seq1
yield seq2
if length % 2 == 1:
yield seq1
consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'z']
vowels = ['a', 'e', 'i', 'o', 'u']
n = int(raw_input().strip())
# Starts with vowel
for comb in itertools.product(*list(alternating(vowels, consonants, n))):
print(''.join(comb))
# Starts with consonant
for comb in itertools.product(*list(alternating(consonants, vowels, n))):
print(''.join(comb))
That way you can reduce the number of possible candidates.
Your approach gave 25**n items, while the new approach only generates 2 * 5**(n//2)*20**(n//2) (if n even) or 5**(n//2 + 1) * 20 ** (n//2) + 5**(n//2) * 20 ** (n//2 + 1) (if n odd) items.
For n=5 that means: What generated originally 9765625 items (almost 10 million!) from product will now only generate 250000 items. Even ignoring the (possibly very expensive) check if your sequence satisfies the problem-condition (which is obsolete now) you generated 40 times more items in your product!

Related

random alphabet chooser with no repeats (python)

import random
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
iterations = 1
running = True
def random_picker():
random_choice = random.choice(alphabet)
iterations =+ 1
print(random_choice)
while running == True:
if iterations <=26:
random_picker()
else:
running == False
I'm trying to get a different random letter through each iteration, through all 26. Each letter picked needs to update the random_choice variable.
Your program will continue looping until 26 letters are returned. Since you want a different letter on each iteration, it's probably easier to shuffle the alphabet array and loop over it instead of trying to choose a random letter in each iteration:
random.shuffle(alphabet)
Paul M. EDIT - Here is an example of how you might use it to achieve the desired effect:
from string import ascii_lowercase
from random import shuffle
alphabet = list(ascii_lowercase)
shuffle(alphabet)
for char in alphabet:
print(char)
Output:
j
m
z
w
k
y
d
f
l
c
u
b
t
s
e
p
x
g
a
r
n
h
i
q
o
v
>>>

Print all possible strings of length k that can be formed from a set of n characters returns >n characters

Python novice here. The goal of the following Code is, to print all possible combinations to pair n characters of the set.
The Problem is that the following code gives an output, that also has more then n characters.
In the Following Code example n=3, but in the Output there are combinations with more then 3.
Code:
def printAllKLength(set, k):
n = len(set)
printAllKLengthRec(set, "", n, k)
def printAllKLengthRec(set, prefix, n, k):
if (k == 0) :
print(prefix)
return
for i in range(n):
newPrefix = prefix + set[i]
printAllKLengthRec(set, newPrefix, n, k-1)
if __name__ == "__main__":
print("First Test")
set1 = ['A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S','T','V','W','Y']
k = 3
printAllKLength(set1, k)
Output:
WNT
WNV
WNW
WNY
WPQA
WPQC
WPQD
WPQE
WPQF
WPQG
WPQH
WPQI
WPQK
WPQL
WPQM
WPQN
WPQPQ
WPQR
WPQS
WPQT
WPQV
WPQW
WPQY
WRA
The aim would be to generate strictly strings of length 3, so if anyone could point me in the right direction, I would be more than grateful.
I rewrote you functions a bit and stripped them to the essentials:
def printAllKLength(set, k):
printAllKLengthRec(set, "", k)
def printAllKLengthRec(set, string, k):
if len(string) == k:
print(string)
return
for c in set:
printAllKLengthRec(set, string + c, k)
return
if __name__ == "__main__":
print("First Test")
set1 = ['A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K',
'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y']
k = 3
printAllKLength(set1, k)
A little hint for next time, break you sample size down to for example len(set1) = 3. then it is far easier to debug and you don't get lost in your own code.
You can use Itertools' combinations function. It takes an iterable and the length of the combination as parameters.
import itertools
num_char = 3
my_set = {'A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y'}
combinations = itertools.combinations(my_set, num_char)
for i in combinations:
print("".join(i))

Python: TypeError: unsupported operand type(s) for +: 'Random' and 'str'

I'm entering a code where a word is randomly generated. But it says TypeError and that random can't be matched with string
I've tried rewriting code multiple times but it didn't work.
Code:
import random
from random import *
Letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
LettersInWord = Random()
Points = 0
print(LettersInWord + " is number of letters in word")
for index in range(LettersInWord):
Word = Letters[Random.random(0, 25)]
Guess = input("Enter Word You Think It Is (You will get a point everytime
one or more of your letters match with the word. Your turn will end when
you enter a letter that is not in the word: ")
for letter in Guess:
if letter == letter in Word:
Points = Points + 1
if Guess == Word:
print("Congratulations, you won. End program and restart to
try again.")
Guess = input("Well done, try again")
Random() is a random-number generator, not a number itself.
letters_in_word = randint(1,25) # random number between 1 and 25, inclusive
(Capitalized names are conventionally reserved for class names. Use snake case identifiers for ordinary variables.)
Continuing from the comments:
from random import *
Letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
while True:
letters_in_word = randint(1,25)
Points = 0
Word = []
print("{} is number of letters in word".format(letters_in_word))
for index in range(0, letters_in_word):
Word.append(Letters[randint(0, 25)])
Guess = input("Press Q/q to exit or Enter Word You Think It Is (You will get a point everytime one or more of your letters match with the word. Your turn will end when you enter a letter that is not in the word: ")
if Guess.lower() == 'q':
break
print(Word)
if Guess in Word:
Points = 100 # assuming
print("Congratulations, you won. End program and restart to try again.\nTotal Points: {}".format(Points))
break
else:
for letter in Guess:
if letter in Word:
Points = Points + 1
print("Total Points: {}".format(Points))
OUTPUT:
10 is number of letters in word
Press Q/q to exit or Enter Word You Think It Is (You will get a point everytime one or more of your letters match with the word. Your turn will end when you enter a letter that is not in the word: pak
['f', 't', 'l', 'b', 'd', 'k', 'e', 'p', 'd', 'n']
Total Points: 2
9 is number of letters in word
Press Q/q to exit or Enter Word You Think It Is (You will get a point everytime one or more of your letters match with the word. Your turn will end when you enter a letter that is not in the word: dirt
['z', 'i', 'k', 'p', 'z', 'j', 'r', 't', 'd']
Congratulations, you won. End program and restart to try again.
Total Points: 100
Process finished with exit code 0

Why do these two programs return different output?

I have two programs that are supposed to reverse a list of chars (strings with length 1). While the second program gives the correct output, the first one doesn't.
Here is program #1:
string = ['h', 'e', 'l', 'l', 'l', 'o']
y = len(string) / 2
for letter in string:
x = string.index(letter)
if x < y:
string[x], string[-1-x] = string[-1-x], string[x]
Here is program #2:
string = ['h', 'e', 'l', 'l', 'l', 'o']
y = len(string) / 2
x = 0
while x < y:
if x < y:
string[x], string[-1-x] = string[-1-x], string[x]
x += 1
My second program successfully reverses the string, but the first one returns ['o', 'e', 'l', 'l', 'l', 'h']. I'm glad I found a solution but would prefer to use .index() rather than counting each loop.
There is an anti-pattern in your first program.
x = string.index(letter)
Consider when you're indexing for the 2nd or 3rd 'l'... x will always be 2. The condition x < y will kick in and reverse the positions of 'e' and the second 'l'.
Here's some debugging:
(Notice that x is 2 at the second, third, and fourth iterations when it should be 2, 3, and 4 respectively.)
Iter 0:
letter = 'h'; x = 0; swap √; string = ['o', 'e', 'l', 'l', 'l', 'h']
# ^------------------------^
Iter 1:
letter = 'e'; x = 1; swap √; string = ['o', 'l', 'l', 'l', 'e', 'h']
# ^--------------^
Iter 2:
letter = 'l'; x = 2; swap √; string = ['o', 'l', 'l', 'l', 'e', 'h']
# ^----^
Iter 3: !
letter = 'l'; x = 2; swap √; string = ['o', 'l', 'l', 'l', 'e', 'h']
# ^----^
Iter 4: !
letter = 'l'; x = 2; swap √; string = ['o', 'e', 'l', 'l', 'l', 'h']
# ^--------------^
Iter 5:
letter = 'l'; x = 5; swap X; string = ['o', 'e', 'l', 'l', 'l', 'h']
Pythonically, you should use enumerate to keep track of the index:
y = len(string) / 2
for i, _ in enumerate(string):
if i < y:
string[i], string[-1-i] = string[-1-i], string[i]
(An underscore was substituted for letter following PEP8 style guides.)
Or even better:
string = string[::-1]
I see that the variable "string" is list of strings. You can reverse it as simple as this:
string = ['h', 'e', 'l', 'l', 'l', 'o']
string.reverse()
string
This should print ['o', 'l', 'l', 'l', 'e', 'h']

Check if a string is in a list of letters - Python3

I have this list which contains letters, and I need to check if a pre-determined word located in another list is horizontally inside this list of letters.
i.e.:
mat_input = [['v', 'e', 'd', 'j', 'n', 'a', 'e', 'o'], ['i', 'p', 'y', 't', 'h', 'o', 'n', 'u'], ['s', 'u', 'e', 'w', 'e', 't', 'a', 'e']]
words_to_search = ['python', 'fox']
I don't need to tell if a word was not found, but if it was I need to tell which one.
My problem is that so far I've tried to compare letter by letter, in a loop similar to this:
for i in range(n): # n = number of words
for j in range(len(word_to_search[i])): # size of the word I'm searching
for k in range(h): # h = height of crossword
for m in range(l): # l = lenght of crossword
But it's not working, inside the last loop I tried several if/else conditions to tell if the whole word was found. How can I solve this?
You can use str.join:
mat_input = [['v', 'e', 'd', 'j', 'n', 'a', 'e', 'o'], ['i', 'p', 'y', 't', 'h', 'o', 'n', 'u'], ['s', 'u', 'e', 'w', 'e', 't', 'a', 'e']]
words_to_search = ['python', 'fox']
joined_input = list(map(''.join, mat_input))
results = {i:any(i in b or i in b[::-1] for b in joined_input) for i in words_to_search}
Output:
{'python': True, 'fox': False}
I'd start by joining each sublist in mat_input into one string:
mat_input_joined = [''.join(x) for x in mat_input]
Then loop over your words to search and simply use the in operator to see if the word is contained in each string:
for word_to_search in words_to_search:
result = [word_to_search in x for x in mat_input_joined]
print('Word:',word_to_search,'found in indices:',[i for i, x in enumerate(result) if x])
Result:
Word: python found in indices: [1]
Word: fox found in indices: []

Categories

Resources