Skip a letter in dictionary - python

I need to assign the uppercase to numbers in a dictionary but with one letter S not there.
ie.
in this alphadict = dict((x, i) for i, x in enumerate(string.ascii_uppercase)) I have currently all the alphabets of the dictionary.
What is the simplest way to delete the entry for S and shift rest of the values to the left.
If there is some other way to create this dictionary do tell.....
I am also in need of this..... Now I get a number from user..... This number in the dictionary should be assigned S and all the other dictionary items can be readjusted....
ie say the user gives me 3 the dictionary should look like
0- A
1- B
2- C
3- S
and rest follow from D to Z without S.......
Please help..... Thanks a lot....

The simplest way is to remove the letter 'S' before you create the dictionary.
Use string.ascii_uppercase.replace('S', '') instead of string.ascii_uppercase.

alphadict = dict((x, i) for i, x in enumerate(string.ascii_uppercase) if x != 'S')

If I understand you properly, the simplest thing to do seems like it would be to first create a list with the letters in the order you want, and then convert that into a dictionary:
import string
sans_S = [c for c in string.ascii_uppercase if c is not 'S']
user_choice = 3
alphabet = sans_S[0:user_choice] + ['S'] + sans_S[user_choice:]
print alphabet
# ['A', 'B', 'C', 'S', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
# 'O', 'P', 'Q', 'R', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
# now create dictionary using modified list
alphadict = dict((x, i) for i, x in enumerate(alphabet))
# print out alphadict sorted by item values (not a necessary part of answer)
revdict = dict( (v,k) for k,v in alphadict.iteritems() )
print '{',
for v in sorted(alphadict.itervalues()):
print "%r:%2d," % (revdict[v], v),
print '}'
# { 'A': 0, 'B': 1, 'C': 2, 'S': 3, 'D': 4, 'E': 5, 'F': 6, 'G': 7, 'H': 8,
# 'I': 9, 'J':10, 'K':11, 'L':12, 'M':13, 'N':14, 'O':15, 'P':16, 'Q':17,
# 'R':18, 'T':19, 'U':20, 'V':21, 'W':22, 'X':23, 'Y':24, 'Z':25, }

for Q2
def makealphabet(i):
a=list(string.ascii_uppercase)
a[i:i]=a.pop(a.index('S'))
return ''.join(a)

If you want to do operations like the one in your update to the question, I would store the data in a list instead of a dictionary right from the beginning:
l = list(string.ascii_uppercase)
l.remove('S')
print l
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
l.insert(3, 'S')
print l
['A', 'B', 'C', 'S', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
The letters can now be accessed by there indices just as if they were in a dictionary.

Related

Alphabet sorting script returns no output (Python)

I am new to programming so cut me some slack. I apologise in advance for asking such a dumb question and thank you for your time.
What I'm trying to do:
I want to make a program that converts letters with their position in the alphabet. I am finding the position of X character by searching it's index in a list (where I have put the alphabet) with a while loop. When all the characters are converted I presumably print the result in a string. But it doesn't have any output when I run it. It doesn't show any errors or warnings so I'm completely lost on what the problem might be.
Why is that and how do I resolve this issue?
Again, thanks for your patiance with me.
Here's the code:
def alphabet_position(text):
alphabet_pos = []
result = ""
index_1 = len(text)
i = 0
while i < index_1:
list_pos = index_1 - 1
character = text[list_pos]
if character.isdigit:
pass
else:
alphabet_low = ['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_cap = ['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']
if character in alphabet_low is True:
alphabet_pos.append(alphabet_low.index(character))
elif character in alphabet_cap is True:
alphabet_pos.append(alphabet_cap.index(character))
else:
pass
i += 1
for char in alphabet_pos:
result = str(alphabet_pos[char]) + " "
char += 1
print(result)
alphabet_position("hello")
Well, there are many things to unpack in your code.
First of all, if character.isdigit: should be replaced with if character.isdigit(): . if character.isdigit: basically asks whether isdigit function is defined and will always return True.
Next, you don't need character in alphabet_low is True, character in alphabet_low is enough.
Next, you don't really use i anywhere and character variable would still be the same letter. Also, you don't need while loop, you can just iterate over the letters of the text.
Next, I don't really understand what you want to do in the last 3 lines before print(result) so I just rewrote it the way I would do it.
I would rewrite your code like this:
def alphabet_position(text):
alphabet_pos = []
result = ""
alphabet_low = ['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_cap = ['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']
for character in text:
if not character.isdigit():
if character in alphabet_low:
alphabet_pos.append(alphabet_low.index(character))
elif character in alphabet_cap:
alphabet_pos.append(alphabet_cap.index(character))
for char in alphabet_pos:
result += str(char) + " "
print('result:', result)
I suggest when you write code, use print statements more often to see how what you've written so far works.
You could also solve it like this:
ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
dct = {y: x for x, y in enumerate(ascii_lowercase)}
def alphabet_position(text):
return [dct[char.lower()] for char in text if char != ' ']
alphabet_position('some text')
# Out[61]: [18, 14, 12, 4, 19, 4, 23, 19]

Why do I keep getting the error "IndexError: list index out of range"?

I don't understand why I am getting this error when I don't believe I am looping out of bounds. The error appears to be in x = lowercase[i + self.num]
class Cipher:
def __init__(self, string, num):
self.string = string
self.num = num
def encrypt(self):
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']
uppercase = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
# establish the array from the inputed string
split = []
for x in range(len(self.string)):
split.append(self.string[x])
for x in split:
for i in range(len(lowercase)):
if (x == lowercase[i]):
x = lowercase[i + self.num]
print(x)
test = Cipher("hello", 1)
test.encrypt()
There is no letter after Z (or z). You have to designate the "next" letter, which is usually A (and a). Therefore, [i + self.num] must be [(i + self.num) % len(lowercase)]. The modulo operator wraps the search around.
x = lowercase[i + self.num] raised index Error if i=25 and self.num=2, so you should use x = lowercase[(i + self.num)%26]
In addition, split = list(self.string) is the better method if you want to convert string to list.

How do you remove a list element

I am trying to make a small program that will jumble up the letters of the alphabet(In simple terms)
I have tried to use things like list.pop() or list.remove(), But those did nothing
import random
def rand_let():
i = 26
alphabet = str('')
for a in range(1, 26):
key = ['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']
print(len(key))
print(key)
letter = random.randint(1, i)
print(key[letter])
letters = key[letter]
alphabet += str(letters)
key.remove(letter)
i -= 1
rand_let()
I want it to jumble up the alphabet,
it is, but the way it is doing it will make letters repeat(I don't want it to repeat)
The shuffle function from random will save you many lines, and does what you're looking for:
import random
alphabet = ['A', 'B', 'C']
random.shuffle(alphabet)
print(alphabet)
#Ex: ['C', 'A', 'B']
The reason you are getting duplicates is that although you have code to remove the letter from the key list, the line that declares the key list is within the loop as well. Try moving the line
key = ['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']
above the for loop. Or, as suggested in other answers, use a library to do this for you.
import random
import string
alphabet = [letter for letter in string.ascii_uppercase]
random.shuffle(alphabet)
print(alphabet)
This will just shuffle the list and then print the elements of the list one by one for each iteration of the for loop.
import random
key = ['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']
random.shuffle(key)
def choice(x):
for letter in key:
print()
choice(key)

Insert element in Python list after every nth element

Say I have a Python list like this:
letters = ['a','b','c','d','e','f','g','h','i','j']
I want to insert an 'x' after every nth element, let's say three characters in that list. The result should be:
letters = ['a','b','c','x','d','e','f','x','g','h','i','x','j']
I understand that I can do that with looping and inserting. What I'm actually looking for is a Pythonish-way, a one-liner maybe?
I've got two one liners.
Given:
>>> letters = ['a','b','c','d','e','f','g','h','i','j']
Use enumerate to get index, add 'x' every 3rd letter, eg: mod(n, 3) == 2, then concatenate into string and list() it.
>>> list(''.join(l + 'x' * (n % 3 == 2) for n, l in enumerate(letters)))
['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']
But as #sancho.s points out this doesn't work if any of the elements have more than one letter.
Use nested comprehensions to flatten a list of lists(a), sliced in groups of 3 with 'x' added if less than 3 from end of list.
>>> [x for y in (letters[i:i+3] + ['x'] * (i < len(letters) - 2) for
i in xrange(0, len(letters), 3)) for x in y]
['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']
(a) [item for subgroup in groups for item in subgroup] flattens a jagged list of lists.
Try this
i = n
while i < len(letters):
letters.insert(i, 'x')
i += (n+1)
where n is after how many elements you want to insert 'x'.
This works by initializing a variable i and setting it equal to n. You then set up a while loop that runs while i is less then the length of letters. You then insert 'x' at the index i in letters. Then you must add the value of n+1 to i. The reason you must do n+1 instead of just n is because when you insert an element to letters, it expands the length of the list by one.
Trying this with your example where n is 3 and you want to insert 'x', it would look like this
letters = ['a','b','c','d','e','f','g','h','i','j']
i = 3
while i < len(letters):
letters.insert(i, 'x')
i += 4
print letters
which would print out
['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']
which is your expected result.
I want to add a new element per item.
How about this ?
a=[2,4,6]
for b in range (0,len(a)):
a.insert(b*2,1)
a is now
[1, 2, 1, 4, 1, 6]
Although using list.insert() in a for loop seems to be more memory efficient, in order to do it in one-line, you can also append the given value at the end of every equally divided chunks split on every nth index of the list.
>>> from itertools import chain
>>> n = 2
>>> ele = 'x'
>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(chain(*[lst[i:i+n] + [ele] if len(lst[i:i+n]) == n else lst[i:i+n] for i in xrange(0, len(lst), n)]))
[0, 1, 'x', 2, 3, 'x', 4, 5, 'x', 6, 7, 'x', 8, 9, 'x', 10]
A pretty straightforward method:
>>> letters = ['a','b','c','d','e','f','g','h','i','j']
>>> new_list = []
>>> n = 3
>>> for start_index in range(0, len(letters), n):
... new_list.extend(letters[start_index:start_index+n])
... new_list.append('x')
...
>>> new_list.pop()
'x'
>>> new_list
['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']
You can also use the grouper recipe from the itertools documentation for the chunking.
This is an old topic, but it lacks the easiest, most "pythonic" solution, imo. It is no more than an extension to part 2 of Mark Mikofski's accepted answer that arguably improves readability (and therefore makes it more pythonic).
>>> letters = ['a','b','c','d','e','f','g','h','i','j']
>>> [el for y in [[el, 'x'] if idx % 3 == 2 else el for
idx, el in enumerate(letters)] for el in y]
['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']
It's worth stating the simple implementation too:
letters = ['a','b','c','d','e','f','g','h','i','j']
i = 3 #initial step
while i < len(letters):
letters.insert(i,'x')
i = i + 3 + 1 #increment step by one for every loop to account for the added element
It does use basic looping and inserting, but it also looks much simpler and comfortable to read than the one-liner examples, which IMHO makes it more Pythonish as requested in the first place.
The for loop already got the option to step up/down with a certain value:
letters = ['a','b','c','d','e','f','g','h','i','j']
n = 3
for i in range ( n, len(letters)+n, n+1 ):
letters.insert ( i, 'X' )
print ( letters )
It does not need divisions or modulo operations, just additions and one size calculation. Output:
['a', 'b', 'c', 'X', 'd', 'e', 'f', 'X', 'g', 'h', 'i', 'X', 'j']
While Mark Mikofski's answer works, there is a faster solution by assigning slices:
import string
# The longer the list the more speed up for list3
# letters = ['a','b','c','d','e','f','g','h','i','j']
letters = list(string.ascii_letters)
print("org:", letters)
# Use enumerate to get index, add 'x' every 3rd letter, eg: mod(n, 3) == 2, then concatenate into string and list() it.
list1 = list(''.join(l + 'x' * (n % 3 == 2) for n, l in enumerate(letters)))
print("list1:", list1)
%timeit list(''.join(l + 'x' * (n % 3 == 2) for n, l in enumerate(letters)))
# But as #sancho.s points out this doesn't work if any of the elements have more than one letter.
# Use nested comprehensions to flatten a list of lists(a), sliced in groups of 3 with 'x' added if less than 3 from end of list.
list2 = [x for y in (letters[i:i+3] + ['x'] * (i < len(letters) - 2) for i in range(0, len(letters), 3)) for x in y]
print("list2:", list2)
%timeit [x for y in (letters[i:i+3] + ['x'] * (i < len(letters) - 2) for i in range(0, len(letters), 3)) for x in y]
# Use list slice assignments
len_letters = len(letters)
len_plus_x = ll // 3
list3 = [None for _ in range(len_letters + len_plus_x)]
list3[::4] = letters[::3]
list3[2::4] = letters[2::3]
list3[1::4] = letters[1::3]
list3[3::4] = ['x' for _ in range(len_plus_x)]
print("list3:", list3)
%timeit ll = len(letters); lp = ll//3; new_letters = [None for _ in range(ll + lp)]; new_letters[::4] = letters[::3]; new_letters[2::4] = letters[2::3]; new_letters[1::4] = letters[1::3]; new_letters[3::4] = ['x' for _ in range(lp)]
produces (using jupyter notebook)
org: ['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']
list1: ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j', 'k', 'l', 'x', 'm', 'n', 'o', 'x', 'p', 'q', 'r', 'x', 's', 't', 'u', 'x', 'v', 'w', 'x', 'x', 'y', 'z', 'A', 'x', 'B', 'C', 'D', 'x', 'E', 'F', 'G', 'x', 'H', 'I', 'J', 'x', 'K', 'L', 'M', 'x', 'N', 'O', 'P', 'x', 'Q', 'R', 'S', 'x', 'T', 'U', 'V', 'x', 'W', 'X', 'Y', 'x', 'Z']
13 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
list2: ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j', 'k', 'l', 'x', 'm', 'n', 'o', 'x', 'p', 'q', 'r', 'x', 's', 't', 'u', 'x', 'v', 'w', 'x', 'x', 'y', 'z', 'A', 'x', 'B', 'C', 'D', 'x', 'E', 'F', 'G', 'x', 'H', 'I', 'J', 'x', 'K', 'L', 'M', 'x', 'N', 'O', 'P', 'x', 'Q', 'R', 'S', 'x', 'T', 'U', 'V', 'x', 'W', 'X', 'Y', 'x', 'Z']
13.7 µs ± 336 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
list3: ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j', 'k', 'l', 'x', 'm', 'n', 'o', 'x', 'p', 'q', 'r', 'x', 's', 't', 'u', 'x', 'v', 'w', 'x', 'x', 'y', 'z', 'A', 'x', 'B', 'C', 'D', 'x', 'E', 'F', 'G', 'x', 'H', 'I', 'J', 'x', 'K', 'L', 'M', 'x', 'N', 'O', 'P', 'x', 'Q', 'R', 'S', 'x', 'T', 'U', 'V', 'x', 'W', 'X', 'Y', 'x', 'Z']
4.86 µs ± 35.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
I would decompose the problem into two problems. First break the list into chunks, then join them with whatever other thing you want to insert.
from itertools import chain
def join_at(elements: list, item: object, n: int) -> list:
# lambda for inserting the element when chunking
insert = lambda i: [] if i == 0 else [item]
# chunk up the original list based on where n lands, inserting the element along the way
chunked = [insert(i) + elements[i:i+n] for i in range(0, len(elements), n)]
# flatten the chunks back out
return list(chain(*chunked))
print(join_at([0,1,2,3,4,5,6,7,8,9], 'x', 3))
This will output the original list of int inserting an x at every 3rd position:
[0, 1, 2, 'x', 3, 4, 5, 'x', 6, 7, 8, 'x', 9]
l = ['a','b','c','d','e','f','g','h','i','j']
[ l.insert(n+(n+1)*i, 'x') for i in range(len(l)/n) ]
print l

Find all combinations of letters, selecting each letter from a different key in a dictionary

Let's say we have this data structure:
class Lock:
def __init__(self):
self.data1 = ['a', 'd', 'e', 'l', 's']
self.data2 = ['s', 'i', 'r', 't', 'n']
self.data3 = ['b', 'o', 'e', 'm', 'k']
self.data4 = ['f', 'y', 'u', 'n', 'g']
Alternatively,
d = {'1': ['a', 'd', 'e', 'l', 's'], '2': ['s', 'i', 'r', 't', 'n'], '3': ['b', 'o', 'e', 'm', 'k'], '4': ['f', 'y', 'u', 'n', 'g'] }
I want to find every possible combination of letters, given that each letter is selected from a different key or array. Order matters, so that the first letter always has to be from 'data1', second has to be from 'data2', etc.
The purpose is to then check these against a dictionary to see which ones are english-valid words. I assumed getting a list of all the combinations, and then doing the check would be the fastest, but if that's not the case, I'd like some input.
Use itertools.product():
for combo in itertools.product(self.data1, self.data2, self.data3, self.data4):
# combo is a tuple of 4 characters.
or:
for combo in itertools.product(*[d[k] for k in sorted(d.keys())]):
# combo is a tuple of 4 characters.
Demo:
>>> import itertools >>> d = {'1': ['a', 'd', 'e', 'l', 's'], '2': ['s', 'i', 'r', 't', 'n'], '3': ['b', 'o', 'e', 'm', 'k'], '4': ['f', 'y', 'u', 'n', 'g'] }
>>> for combo in itertools.product(*[d[k] for k in sorted(d.keys())]):
... print ''.join(combo)
...
asbf
asby
asbu
asbn
asbg
asof
asoy
asou
ason
asog
asef
...
snkf
snky
snku
snkn
snkg
Good answer from Martin, itertools.product is the best way. Since it was introduced in version 2.6, you can get back to old-fashioned style for Python 2.5 and earlier:
>>> [i1 + i2 + i3 + i4 for i1 in data1 for i2 in data2 for i3 in data3 for i4 in data4 ]
['asbf', 'asby', 'asbu', 'asbn', 'asbg', 'asof', 'asoy', 'asou', 'ason', 'asog', 'asef',
'asey', 'aseu', 'asen', 'aseg', 'asmf', 'asmy', 'asmu', 'asmn', 'asmg', 'askf', 'asky',
'asku', 'askn', 'askg', 'aibf', 'aiby', 'aibu', 'aibn', 'aibg', 'aiof', 'aioy', 'aiou',
'aion', 'aiog', 'aief', 'aiey', 'aieu', 'aien', 'aieg', 'aimf', 'aimy', 'aimu', 'aimn',
'aimg', 'aikf', 'aiky', 'aiku', 'aikn', 'aikg', 'arbf', 'arby', 'arbu', 'arbn', 'arbg',
'arof', 'aroy', 'arou', 'aron', 'arog', 'aref', 'arey', 'areu', 'aren', 'areg', 'armf',
'army', 'armu', 'armn', 'armg', 'arkf', 'arky', 'arku', 'arkn', 'arkg', 'atbf', 'atby',
'atbu', 'atbn', 'atbg', 'atof', 'atoy', 'atou', 'aton', 'atog', 'atef', 'atey', 'ateu'
...
Not using itertools:
def combination(x):
list1 = g.values()[0]
list2 = g.values()[1]
for i in list1:
for j in list2:
print(i+j)
combination({'1':['a','b'], '2':['c','d']})
x={'1':['a','b'], '2':['c','d']}
list1 = x.get('1')
list2 = x.get('2')
for i in range(2):
for j in range(2):
print(list1[i]+list2[j])

Categories