prints results only when string item index == list item index - python

I've been working on a little project of mine lately, but I've run into a problem that I'm stuck at. I've already checked various places, but I couldn't really find what I'm looking for. This is my code:
special_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]
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']
name = input('Please insert your name: ')
item_alphabet = -1
item_special_alphabet = -1
index = -1
for item in name:
item_alphabet = item_alphabet + 1
item_special_alphabet = item_special_alphabet + 1
index = index + 1
if alphabet[item_alphabet] == name[index]:
print(special_alphabet[item_special_alphabet])
The special_alphabet list contains the special characters that I have in variables. I didn't display them because they're too long, but they're there.
The problem I'm having right now is that when I run this code and type in my input, it does actually check the 'name' (string) I've inserted, it just does it in order of the list(alphabet basically). So when I enter: Amine, it only returns the special character for A (because it's the first (0) in both the string and the list) and E (same reason, just it's fifth.)
What I'm looking for is how to make it go through the whole list without any order whatsoever and check all the items in it before running the if statement and printing out the special characters.
Thank you in advance.

You can use str.maketrans() and str.translate() for these kinds of translation jobs:
trans_tab = str.maketrans(dict(zip(alphabet, special_alphabet)))
name = input('Please insert your name: ')
translated_name = name.translate(trans_tab)
print(translated_name)
If you pass str.maketrans() a single dictionary argument that consists of strings of length 1 as keys and arbitrary length strings as values, it'll build you a translation table usable with str.translate(), which creates a new copy of the string where each character has been mapped through the given translation table.
For example:
In [15]: trans = str.maketrans({
...: 'A': 'A ',
...: 'm': 'M ',
...: 'i': 'I ',
...: 'n': 'N ',
...: 'e': 'E '
...: })
In [16]: input("> ").translate(trans)
> Amine
Out[16]: 'A M I N E '

A dictionary of alphabet and spacial alphabet may be a best design
in your case try;
for item in name:
ind = alphabet.find(item)
if ind != -1:
print(special_alphabet[ind])

Related

replace each character with the first greater character after it

I am trying to replace each character with the next greater character after it and if there is no greater character after it then replace it by '#'
if I have a circular list of characters [K, M, Y, R, E, J, A]
the output should be [M, Y, #, Y, J, K, K]
'M is greater than k so replace K with M and Y is greater than M so replace M with Y and so one ( greater here means comes after it )'
this is the code that I have tried but it gives wrong output
def que1(input_list):
for i in range (len (input_list)-1) :
j=i+1
for j in range (len(input_list)-1):
if input_list[i]<input_list[j]:
input_list[i]=input_list[j]
if input_list[i]>input_list[j]:
input_list[i]='#'
return input_list
Another way to do it :
def que1(i_list):
input_list=i_list*2
output_list=[]
for i in range (len (i_list)) :
found=False
for j in range (i+1,len(input_list)-1):
if input_list[i]<input_list[j]:
output_list.append(input_list[j])
found=True
break
if not found:
output_list.append('#')
return output_list
output:
['M', 'Y', '#', 'Y', 'J', 'K', 'K']
The following code should do what you want.
def que1(input_list):
output_list = []
# loop through the input list with index
for index, c in enumerate(input_list):
# split list at c and create new list
# [all greater characters after c, all greater character before c]
tmp = [i for i in input_list[index:] if i > c] + [i for i in input_list[:index] if i > c]
# if list empty there is no greater character
if len(tmp) == 0:
output_list.append('#')
# else choose the first greater character
else:
output_list.append(tmp[0])
return output_list
Input: ['K', 'M', 'Y', 'R', 'E', 'J', 'A']
Output: ['M', 'Y', '#', 'Y', 'J', 'K', 'K']
Here is another way to do it.
def next_greatest(data):
out = []
for idx in range(len(data)):
char = data[idx]
cs = iter(data[idx + 1:] + data[:idx])
while True:
try:
curr = next(cs)
except StopIteration:
out.append("#")
break
if curr > char:
out.append(curr)
break
return out
next_greatest(chars)
>> ['M', 'Y', '#', 'Y', 'J', 'K', 'K']

Scratch lottery function

I am working on a scratch lottery command on my python game.
My Scratch lottery function is below.
def lottery(player_money):
print('scratch lottery :')
print('price: 500')
print('wins :')
print(' all 6 same : $100000')
print(' all 5 same : $50000')
print(' all 4 same : $10000')
print(' all 3 same : $1000')
print(' all 2 same : $300')
print('do you want to buy it?? yes/no')
buy = input('> ')
if buy == 'no':
print('please come back later!!')
return player_money
elif buy == 'yes':
print('_____________')
lottery_results = ['x', 'o', 'p', 'k', 'm', 'e', 'a', 'w']
a = random.choice(lottery_results)
b = random.choice(lottery_results)
c = random.choice(lottery_results)
d = random.choice(lottery_results)
e = random.choice(lottery_results)
f = random.choice(lottery_results)
print('| ' + a + ' | ' + b + ' | ' + c + ' |')
print('|_' + d + '_|_' + e + '_|_' + f + '_|')
if...
I Have no idea what to put after
if...
I don't want to make if for all possible solutions since that would be like 2 million ifs.
I want to make it like below
If 2 of the str in a or b or c or d or e or f is the same:
print('Since 2 matched, you won $300!')
player_money += 300
return player_money
I don't know how to code(ify) the phrase that goes after if and the phrase that goes after if that I put in wouldn't work and there would be a error
Any suggestions on how I could make this work?
You're off to a good start, but there is something that could make your life a lot easier. Firstly, lets use random.choices to create a list from the possible letters:
import random
pool = ['x', 'o', 'p', 'k', 'm', 'e', 'a', 'w']
results = random.choices(pool, k=len(pool))
Note: k can be any integer - it determines the length of the resulting list
This is going to yield a list with random letters from the pool:
['e', 'x', 'a', 'm', 'x', 'k', 'o', 'p']
Now, you can think about how you can build your if statement off of a list.
If 2 of the str in a or b or c or d or e or f is the same:
This sounds like a job for iteration. Remember, we don't have the variables a, b, c, etc. anymore; rather, they're stored in a list.
for letter in pool:
if results.count(letter) > 1:
# match found
Above, you iterate through the pool variable, which holds all of the possible values. On every loop of that iteration, we check if the current letter that resides inside the pool list exists more than once in the results list. This means that there was a match.
More
You can dynamically increase the player's money count with only a few lines if you keep a list of the possible winnings that correspond with a certain number of matches. For example,
winnings = [100, 200, 300, 400, 500, 600, 700, 800]
Here, 100 is chosen if there are two of the same letter (1 match). If there are three of the same letter (2 matches), 200 is chosen.
player_money = 0
for letter in pool:
result_count = results.count(letter)
player_money += winnings[result_count-2] if result_count > 1 else 0
Above, the line winnings[result_count-2] if result_count > 1 else 0 determines how much the player should receive based off of their matches. We have to subtract 2 from result_count because, remember, python indexing starts from 0, and if there are two of the same letter in the resulting list (1 match), we need to subtract 2 to make it 0, which selects the correct winnings.
If you want to go by your own code then, You can use Counter.
from itertools import Counter
then you can use it like:
Counter([a,b,c,d,e,f]))
to check if any of the values is 2.
Use random.sample() to gather 6 results in a single line.
Then we can simply loop over the sample and check if each draw exists in lottery_results. It also may be better to store the winnings in a dict so we can easily retrieve the amount without too much hassle.
import random
winnings = {6: 100000, 5: 50000, 4: 10000, 3: 1000, 2: 300}
lottery_results = ['x', 'o', 'p', 'k', 'm', 'e', 'a', 'w']
user_numbers = random.sample(lottery_results, 6)
#['m', 'k', 'e', 'a', 'x', 'p']
matches = 0
for draw in user_numbers:
if draw in lottery_results:
matches += 1
print(f'Congrats! You matched {matches} and won ${winnings[matches]}')
#Congrats! You matched 6 and won $100000
You have further issues with the way you have set out to achieve your goal. You're generating the results for the draw from the results of the house. This means you will always match 6.
We can show this by implementing a possible_draws to generate both our results and user draws from. We will use the alphabet as an example.
import string
possible_draws = list(string.ascii_lowercase)
#['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']
lottery_results = random.sample(possible_draws, 8)
#['x', 'h', 'o', 'p', 'j', 'n', 'm', 'c']
user_draws = random.sample(possible_draws, 6)
#['h', 'r', 'u', 't', 'f', 'n']
matches = 0
for draw in user_draws:
if draw in lottery_results:
matches += 1
if matches < 2:
print('No win this time!')
else:
print(f'Congrats! You matched {matches} and won ${winnings[matches]}')

Nesting a function inside itself (i'm desperate)

Mentally exhausted.
An explanation just for context, dont actually need help with hashes:
I'm trying to make a python script that can bruteforce a hashed string or password (learning only, i'm sure there are tenter code herehousands out there).
The goal is making a function that can try all the possible combinations of different letters, starting from one character (a, b... y, z) and then start trying with one more character (aa, ab... zy, zz then aaa, aab... zzy, zzz) indefinetly until it finds a match.
First, it asks you for a string (aaaa for example) then it hashes the string, and then try to bruteforce that hash with the function, and finally the function returns the string again when it finds a match.
PASSWORD_INPUT = input("Password string input: ")
PASSWORD_HASH = encrypt_password(PASSWORD_INPUT) # This returns the clean hash
found_password = old_decrypt() # This is the function below
print(found_password)
I managed to do this chunk of ugly ass code:
built_password = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
def old_decrypt():
global built_password
# First letter
for a in range(len(characters)): # Characters is a list with the abecedary
built_password[0] = characters[a]
if test_password(pretty(built_password)): # This returns True if it matches
return pretty(built_password)
# Second letter
for b in range(len(characters)):
built_password[1] = characters[b]
if test_password(pretty(built_password)):
return pretty(built_password)
# Third letter
for c in range(len(characters)):
built_password[2] = characters[c]
if test_password(pretty(built_password)):
return pretty(built_password)
# Fourth letter
for d in range(len(characters)):
built_password[3] = characters[d]
if test_password(pretty(built_password)):
return pretty(built_password)
The problem of this is that it only works with 4 letters strings.
As you can see, it's almost the exact same loop for every letter, so i thought "Hey i can make this a single function"... After obsessively trying everything that came to my mind for 3 whole days i came with this:
# THIS WORKS
def decrypt(letters_amount_int):
global built_password
for function_num in range(letters_amount_int):
for letter in range(len(characters)):
built_password[function_num] = characters[letter]
if letters_amount_int >= 1:
decrypt(letters_amount_int - 1)
if test_password(pretty(built_password)):
return pretty(built_password)
# START
n = 1
while True:
returned = decrypt(n)
# If it returns a string it gets printed, else trying to print None raises TypeError
try:
print("Found hash for: " + returned)
break
except TypeError:
n += 1
Function gets a "1", tries with 1 letter and if it doesnt return anything it gets a "2" and then tries with 2.
It works, but for some reason it makes a ridiculous number of unnecessary loops that takes exponentially more and more time, i've been smashing my head and came to the conclussion that i'm not understanding something about python's internal functioning.
Can someone please drop some light on this? Thanks
In case of needed these are the other functions:
def encrypt_password(password_str):
return hashlib.sha256(password_str.encode()).hexdigest()
def test_password(password_to_test_str):
global PASSWORD_HASH
if PASSWORD_HASH == encrypt_password(password_to_test_str):
return True
characters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'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', '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']
Recursion in this case gives a very elegant solution:
def add_char(s, limit):
if len(s) == limit:
yield s
else:
for c in characters:
yield from add_char(s + c, limit)
def generate_all_passwords_up_to_length(maxlen):
for i in range(1, maxlen + 1):
yield from add_char("", i)
for password in generate_all_passwords_up_to_length(5):
test_password(password)
Maybe you could try something like this. Inspired by Multiple permutations, including duplicates
Itertools has a cartesian product generator, which is related to permutation.
import itertools
def decrypt(characters, num_chars):
for test_list in itertools.product(characters, repeat=num_chars):
test_str = ''.join(test_list)
if test_password(test_str):
return test_str
return None
for i in range(min_chars, max_chars+1):
result = decrypt(characters, i)
if result:
print(f'Match found: {result}')
If you run this code with characters, min_chars, max_chars = (characters, 1, 3) and print test_str at each step, you'll get:
0
1
2
00
01
02
10
11
12
20
21
22
or will stop earlier if a match is found. I recommend you look up a recursive, pure python implementation of the the cartesian product function if you want to learn more. However, I'd suspect the cartesian product generator will be faster than a recursive solution.
Note that itertools.product() is a generator, so it's generating each value on demand, and writing it this way allows you to find a match for shorter strings faster than longer ones. But the time it takes this brute force algorithm should indeed increase exponentially with the length of the true password.
Hope this helps.

Multiply an integer in a list by a word in the list

I'm not sure how to multiply a number following a string by the string. I want to find the RMM of a compound so I started by making a dictionary of RMMs then have them added together. My issue is with compounds such as H2O.
name = input("Insert the name of a molecule/atom to find its RMM/RAM: ")
compound = re.sub('([A-Z])', r' \1', name)
Compound = compound.split(' ')
r = re.split('(\d+)', compound)
For example:
When name = H2O
Compound = ['', 'H2', 'O']
r = ['H', '2', 'O']
I want to multiply 2 by H making a value "['H', 'H', 'O']."
TLDR: I want integers following names in a list to print the previously listed object 'x' amount of times (e.g. [O, 2] => O O, [C, O, 2] => C O O)
The question is somewhat complicated, so let me know if I can clarify it. Thanks.
How about the following, after you define compound:
test = re.findall('([a-zA-z]+)(\d*)', compound)
expand = [a*int(b) if len(b) > 0 else a for (a, b) in test]
Match on letters of 1 or more instances followed by an optional number of digits - if there's no digit we just return the letters, if there is a digit we duplicate the letters by the appropriate value. This doesn't quite return what you expected - it instead will return ['HH', 'O'] - so please let me know if this suits.
EDIT: assuming your compounds use elements consisting of either a single capital letter or a single capital followed by a number of lowercase letters, you can add the following:
final = re.findall('[A-Z][a-z]*', ''.join(expand))
Which will return your elements each as a separate entry in the list, e.g. ['H', 'H', 'O']
EDIT 2: with the assumption of my previous edit, we can actually reduce the whole thing down to just a couple of lines:
name = raw_input("Insert the name of a molecule/atom to find its RMM/RAM: ")
test = re.findall('([A-z][a-z]*)(\d*)', name)
final = re.findall('[A-Z][a-z]*', ''.join([a*int(b) if len(b) > 0 else a for (a, b) in test]))
You could probably do something like...
compound = 'h2o'
final = []
for x in range(len(compound)):
if compound[x].isdigit() and x != 0:
for count in range(int(compound[x])-1):
final.append(compound[x-1])
else:
final.append(compound[x])
Use regex and a generator function:
import re
def multilpy_string(seq):
regex = re.compile("([a-zA-Z][0-9])|([a-zA-Z])")
for alnum, alpha in regex.findall(''.join(seq)):
if alnum:
for char in alnum[0] * int(alnum[1]):
yield char
else:
yield alpha
l = ['C', 'O', '2'] # ['C', 'O', 'O']
print(list(multilpy_string(l)))
We join your list back together using ''.join. Then we compile a regex pattern that matches two types of strings in your list. If the string is a letter and is followed by a number its put in a group. If its a single number, its put in its own group. We then iterate over each group. If we've found something in a group, we yield the correct values.
Here are a few nested for comprehensions to get it done in two lines:
In [1]: groups = [h*int(''.join(t)) if len(t) else h for h, *t in re.findall('[A-Z]\d*', 'H2O')]
In[2]: [c for cG in groups for c in cG]
Out[2]: ['H', 'H', 'O']
Note: I am deconstructing and reconstructing strings so this is probably not the most efficient method.
Here is a longer example:
In [2]: def findElements(molecule):
...: groups = [h*int(''.join(t)) if len(t) else h for h, *t in re.findall('[A-Z]\d*', molecule)]
...: return [c for cG in groups for c in cG]
In [3]: findElements("H2O5S7D")
Out[3]: ['H', 'H', 'O', 'O', 'O', 'O', 'O', 'S', 'S', 'S', 'S', 'S', 'S', 'S', 'D']
In python3 (I don't know about python2) you can simply multiply strings.
for example:
print("H"*2) # HH
print(2*"H") # HH
Proof that this information is useful:
r = ['H', '2', 'O']
replacements = [(index, int(ch)) for index, ch in enumerate(r) if ch.isdigit()]
for postion, times in replacements:
r[postion] = (times - 1) * r[postion - 1]
# flaten the result
r = [ch for s in r for ch in s]
print(r) # ['H', 'H', 'O']

Replacing Multiple Letters in a String with Each Other in Python [duplicate]

This question already has answers here:
Replace multiple elements in string with str methods
(2 answers)
Closed 8 years ago.
So I understand how to use str.replace() to replace single letters in a string, and I also know how to use the following replace_all function:
def replace_all(text, dic):
for i, j in dic.iteritems():
text = text.replace(i,j)
return text
But I am trying to replace letters with each other. For example replace each A with T and each T with A, each C with G and each G with C, but I end up getting a string composed of only two letters, either A and G or C and T, for example, and I know the output should be composed of four letters. Here is the code I have tried (I'd rather avoid built in functions):
d={'A': 'T', 'C': 'G', 'A': 'T', 'G': 'C'}
DNA_String = open('rosalind_rna.txt', 'r')
DNA_String = DNA_String.read()
reverse = str(DNA_String[::-1])
def replace_all(text, dic):
for i, j in dic.iteritems():
text = text.replace(i,j)
return text
complement = replace_all(reverse, d)
print complement
I also tried using:
complement = str.replace(reverse, 'A', 'T')
complement = str.replace(reverse, 'T', 'A')
complement = str.replace(reverse, 'G', 'C')
complement = str.replace(reverse, 'C', 'G')
But I end up getting a string that is four times as long as it should be.
I've also tried:
complement = str.replace(reverse, 'A', 'T').replace(reverse, 'T', 'A').replace(reverse, 'G', 'C')str.replace(reverse, 'C', 'G')
But I get an error message that an integer input is needed.
You can map each letter to another letter.
>>> M = {'A':'T', 'T':'A', 'C':'G', 'G':'C'}
>>> STR = 'CGAATT'
>>> S = "".join([M.get(c,c) for c in STR])
>>> S
'GCTTAA'
You should probably use str.translate for this. Use string.maketrans to create an according transition table.
>>> import string
>>> d ={'A': 'T', 'C': 'G', 'G': 'C', 'T': 'A'}
>>> s = "ACTG"
>>> _from, to = map(lambda t: ''.join(t), zip(*d.items()))
>>> t = string.maketrans(_from, to)
>>> s.translate(t)
'TGAC'
By the way, the error you get with this line
complement = str.replace(reverse, 'A', 'T').replace(reverse, 'T', 'A')...
is that you are explicitly passing the self keyword when it is passed implicitly. Doing str.replace(reverse, 'A', 'T') is equivalent to reverse.replace('A', 'T'). Accordingly, when you do str.replace(...).replace(reverse, 'T', 'A'), this is equivalent to str.replace(str.replace(...), reverse, 'T', 'A'), i.e. the result of the first replace is inserted as self in the other replace, and the other parameters are shifted and the 'A' is interpreted as the count parameter, which has to be an int.
I think this is happening because you're replacing all the As with Ts and then replacing all those Ts (as well as those in the original string) with As. Try replacing with lower-case letters and then converting the whole string with upper():
dic = {'A': 't', 'T': 'a', 'C': 'g', 'G': 'c'}
text = 'GATTCCACCGT'
for i, j in dic.iteritems():
text = text.replace(i,j)
text = text.upper()
gives:
'CTAAGGTGGCA'

Categories

Resources