Objective: count by letters instead of integers.
Is there a clean way to count-by-letters in Python-2.7? I have a program where I am enumerating some data by letter, and my solution would not be very clear to someone reading my code.
I've been checking through the standard documentation, but I don't see anything built-in.
What I'm looking for:
for count in range('A', 'G'):
print count
output[1]:
'C'
'D'
'E'
'F'
How I would do it:
Solution A: Use a dictionary
letters = {
1:'A'
2:'B'
3:'C'
...
}
for count in range(2, 6):
print letters[count]
Solution B: Use chr() and ord()
for count in range(2, 6):
print chr(ord('A') + count)
Relevance:
I am working on a sunday paper crytogram solver. Part of my algorithm involves classifying words by their letter code. For example,
print letter_code('banana')
output[2]: 'ABCBCB'
import string
alphabet = string.ascii_uppercase
>>> for char in alphabet[2:6]:
... print char
...
C
D
E
F
>>>
Your Solution B could be expressed:
for charcode in range(ord('B'), ord('G')):
print chr(charcode)
But to attack your larger issue, how about:
from string import ascii_lowercase, ascii_uppercase
def letter_code(string):
indexes = [ascii_lowercase.index(letter) for letter in string]
return "".join(ascii_uppercase[indexes.index(number)] for number in indexes)
print letter_code('banana')
Gives you "ABCBCB"
Here is a function that would do what you wish:
import string
def enumerate(first, last):
alphabet = string.ascii_uppercase
start = alphabet.index(first)
while alphabet[start] != last:
print alphabet[start]
start += 1
print last
Another solution I have become fond of for my particular application is:
alphabet = iter('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
print next(alphabet)
Related
Problem:
Given a string s consisting of small English letters, find and return the first instance of a non-repeating character in it. If there is no such character, return '_'.
Example
For s = "abacabad", the output should be
firstNotRepeatingCharacter(s) = 'c'.
This is what I have so far, but it's too slow. How can I make the run time faster? Thanks.
def firstNotRepeatingCharacter(s):
char = set(s)
for i in range(len(s)):
if s.count(s[i]) == 1:
return s[i]
return "_"
You could use collections.Counter to count the characters in linear time, and then filter the result in conjunction with next, like this:
from collections import Counter
def firstNotRepeatingCharacter(s):
counts = Counter(s)
return next((ch for ch in s if counts[ch] < 2), "_")
print(firstNotRepeatingCharacter("abacabad"))
Output
c
Or simply use a dictionary (no imports needed):
counts = {}
for ch in s:
counts[ch] = counts.get(ch, 0) + 1
return next((ch for ch in s if counts[ch] < 2), "_")
Both approaches are linear in the length of the input string, your current approach is O(k*s) where k is the number of unique characters.
Write a while loop that takes a string and counts the vowels. Use the string “May the force be with you.” Print the results. (Answer: 8)
Any help with this would be greatly appreciated! I kept coming up with a continuous loop. It has to use a while loop and print the number of vowels (8). Thank you!!
count = 0
vowels = ['a', 'e', 'i', 'o', 'u']
s = "May the force be with you."
while i in s:
if i in vowels:
count += 1
print(count)
The statement:
while i in s:
does not do what you think. Were that while a for, it would iterate over the string one character at a time, and probably work.
However, the expression i in s (which is what that is in a while statement) simply checks if i is one of the things in the s "collection" and gives you true or false. It does not iterate i over the s collection.
If i had been set to something, the while loop would either execute infinitely or never, depending on the value of i. If i is not bound to a value, you'll get a run-time error.
As a solution, you can iterate over the characters in a string with something like (from an actual transcript):
>>> str = "pax"
>>> for ch in str:
... print(ch)
...
p
a
x
The equivalent while version would be:
>>> str = "pax"
>>> idx = 0 # OR: idx, slen = 0, len(str)
>>> while idx < len(str): # while idx < slen:
... print str[idx]
... idx += 1
...
p
a
x
though the for variant is generally considered more Pythonic for this sort of task.
Further, you can detect if a character is one of a set of characters by using in, such as in the following transcript:
>>> str = "pax"
>>> for ch in str:
... if ch in "ABCabc":
... print(f"{ch} is either a, b, or c")
...
a is either a, b, or c
So you should be able to combine that for/while loop and if statement to count the vowels and output it (with print).
Note especially the string I use for vowel checking, it also contains the upper-case vowels. And keep in mind, though your specification may only be to use the Latin-ish vowels, the Unicode world of today would not forgive this oversight. See here for example.
Since it needs to be a while, you can slice off a character at a time and loop until the string is empty. As a quick optimization, True adds as 1 and False as 0, so the interior if can be removed.
vowels = ['a', 'e', 'i', 'o', 'u']
s = "May the force be with you."
count = 0
while s:
count += s[0] in vowels
s = s[1:]
print(count)
I think you could use something like this
phrase = "May the force be with you."
vowels = 0
count = 0
while phrase[count] != ".":
if phrase[count] in 'aeiou':
vowels += 1
count+=1
print(vowels)
input: ['baNaNa', 7] # string and step size
required output : 'utGtGt' # every character of string shifted backwards by step size
import ast
in_string = input()
lis = ast.literal_eval(in_string)
st = lis[0]
step = lis[1]
alphabets = 'abcdefghijklmnopqrstuvwxyz'
password = ''
for letter in st:
if letter in alphabets:
index_val = alphabets.index(letter) - (step)
password += alphabets[index_val]
print(password)
Output i am getting is 'utgtgt'. I want 'utGtGt'. Help on this would be appreciated a lot.
The string module has methods to create a transformation dictionary and a translate method to do exactly what you want:
st = "baNaNa"
step = 7
alphabets = 'abcdefghijklmnopqrstuvwxyz'
alph2 = alphabets.upper()
# lower case translation table
t = str.maketrans(alphabets, alphabets[-step:]+alphabets[:-step])
# upper case translation table
t2 = str.maketrans(alph2, alph2[-step:]+alph2[:-step])
# merge both translation tables
t.update(t2)
print(st.translate(t))
Output:
utGtGt
You give it the original string and an equal long string to map letters to and apply that dictionary using str.translate(dictionary).
The sliced strings equate to:
print(alphabets)
print(alphabets[-step:]+alphabets[:-step])
abcdefghijklmnopqrstuvwxyz
tuvwxyzabcdefghijklmnopqrs
which is what your step is for.
See Understanding slice notation if you never saw string slicing in use.
by processing each charater and checking it's cardinal no and making calculation accordingly help you to reach the result
def func(string, size):
if size%26==0:
size=26
else:
size=size%26
new_str = ''
for char in string:
if char.isupper():
if ord(char)-size<ord('A'):
new_str+=chr(ord(char)-size+26)
else:
new_str+=chr(ord(char)-size)
elif char.islower():
if ord(char)-size<ord('a'):
new_str+=chr(ord(char)-size+26)
else:
new_str+=chr(ord(char)-size)
return new_str
res =func('baNaNa', 7)
print(res)
# output utGtGt
Here's a simple solution that makes use of the % modulo operator to shift letters backwards.
It basically collects all of the letters in a reverse index lookup dictionary, so looking up letter positions is O(1) instead of using list.index(), which is linear O(N) lookups.
Then it goes through each letter and calculates the shift value from the letter index e.g. for the letter a with a shift value of 7, the calculation will be (0 - 7) % 26, which will give 19, the position of u.
Then once you have this shift value, convert it to uppercase or lowercase depending on the case of the original letter.
At the end we just str.join() the result list into one string. This is more efficient than doing += to join strings.
Demo:
from string import ascii_lowercase
def letter_backwards_shift(word, shift):
letter_lookups = {letter: idx for idx, letter in enumerate(ascii_lowercase)}
alphabet = list(letter_lookups)
result = []
for letter in word:
idx = letter_lookups[letter.lower()]
shifted_letter = alphabet[(idx - shift) % len(alphabet)]
if letter.isupper():
result.append(shifted_letter.upper())
else:
result.append(shifted_letter.lower())
return ''.join(result)
Output:
>>> letter_backwards_shift('baNaNa', 7)
utGtGt
I would probably go with #Patrick Artner's pythonic solution. I just showed the above implementation as a learning exercise :-).
Prompt
Turn a string into rollercoaster case. The first letter of the sentence is uppercase, the next lowercase, the next uppercase, and so on.
Code
with open('test.txt') as file:
for line in file:
words = line.split()
for word in words:
chars = list(word)
for index, char in enumerate(chars):
if index == 0:
print char.upper(),
elif is_even(index):
print char.upper(),
elif is_odd(index):
print char,
Input
Sunshine makes me happy, on a cloudy day
Output
S u N s H i N e M a K e S M e H a P p Y , O n A C l O u D y D a Y
This is my first attempt at this problem. I can't think of any other way to do this other than to iterate by each letter. When I do this though I'm just treating the entire sentence as a string and spewing out characters.
You can uppercase just every second letter with an extended slice, picking every second letter:
>>> sample = 'Sunshine makes me happy, on a cloudy day'
>>> sample[::2].upper()
'SNHN AE EHPY NACOD A'
>>> sample[1::2].lower()
'usiemksm ap,o luydy'
Now all you need to do is put those together again:
from itertools import izip_longest
result = ''.join([l
for pair in izip_longest(sample[::2].upper(), sample[1::2].lower(), fillvalue='')
for l in pair])
izip_longest() pairs up the uppercased and lowercased strings again, making sure that if there is an odd number of characters to pad out the series with an empty string.
Demo:
>>> from itertools import izip_longest
>>> ''.join([l
... for pair in izip_longest(sample[::2].upper(), sample[1::2].lower(), fillvalue='')
... for l in pair])
'SuNsHiNe mAkEs mE HaPpY, oN A ClOuDy dAy'
Note that whitespace isn't ignored here; the m of make is lowercased even though the e at the end of Sunshine is too.
If you need to vary the letters more precisely, you can make use of iteration still:
from itertools import cycle
from operator import methodcaller
methods = cycle((methodcaller('upper'), methodcaller('lower')))
result = ''.join([next(methods)(c) if c.isalpha() else c for c in sample])
Here itertools.cycle() lets us alternate between two operator.methodcaller() objects, which either upper or lowercase the argument passed in. We only advance to the next one (using next()) when the character is a letter.
Demo:
>>> from itertools import cycle
>>> from operator import methodcaller
>>> methods = cycle((methodcaller('upper'), methodcaller('lower')))
>>> ''.join([next(methods)(c) if c.isalpha() else c for c in sample])
'SuNsHiNe MaKeS mE hApPy, On A cLoUdY dAy'
If it's whitespace giving you trouble, you should use isalpha() to test if a character is a letter or not.
with open('test.txt') as file:
for line in file:
newstr = ""
go_to_upper = True
for c in line:
if c.isalpha():
if go_to_upper:
newstr += c.upper()
else:
newstr += c.lower()
go_to_upper = not go_to_upper
else:
newstr += c
print newstr
Input: Sunshine makes me happy, on a cloudy day
Output: SuNsHiNe MaKeS mE hApPy, On A cLoUdY dAy
You'll only flip back and forth (using the go_to_upper boolean) when the character in question is a letter of the alphabet. Otherwise, it's outputted normally. Notice that MaKeS starts with a capital letter, though SuNsHiNe ends with a lowercase letter, even with the space in the way.
Also, instead of printing immediately (which gives you the weird spacing) we're putting our characters in a new list, which we'll print out all at once later.
Try this code :
import re
i = 1
with open('test.txt') as file:
for line in file:
words = line.split()
for word in words:
chars = list(word)
for index, char in enumerate(chars):
if re.compile('[a-zA-Z]').search(char):
i+=1
if i%2 !=0:
print char.upper(),
else :
print char.lower(),
As an example, lets say I wanted to list the frequency of each letter of the alphabet in a string. What would be the easiest way to do it?
This is an example of what I'm thinking of... the question is how to make allTheLetters equal to said letters without something like allTheLetters = "abcdefg...xyz". In many other languages I could just do letter++ and increment my way through the alphabet, but thus far I haven't come across a way to do that in python.
def alphCount(text):
lowerText = text.lower()
for letter in allTheLetters:
print letter + ":", lowertext.count(letter)
The question you've asked (how to iterate through the alphabet) is not the same question as the problem you're trying to solve (how to count the frequency of letters in a string).
You can use string.lowercase, as other posters have suggested:
import string
allTheLetters = string.lowercase
To do things the way you're "used to", treating letters as numbers, you can use the "ord" and "chr" functions. There's absolutely no reason to ever do exactly this, but maybe it comes closer to what you're actually trying to figure out:
def getAllTheLetters(begin='a', end='z'):
beginNum = ord(begin)
endNum = ord(end)
for number in xrange(beginNum, endNum+1):
yield chr(number)
You can tell it does the right thing because this code prints True:
import string
print ''.join(getAllTheLetters()) == string.lowercase
But, to solve the problem you're actually trying to solve, you want to use a dictionary and collect the letters as you go:
from collections import defaultdict
def letterOccurrances(string):
frequencies = defaultdict(lambda: 0)
for character in string:
frequencies[character.lower()] += 1
return frequencies
Use like so:
occs = letterOccurrances("Hello, world!")
print occs['l']
print occs['h']
This will print '3' and '1' respectively.
Note that this works for unicode as well:
# -*- coding: utf-8 -*-
occs = letterOccurrances(u"héĺĺó, ẃóŕĺd!")
print occs[u'l']
print occs[u'ĺ']
If you were to try the other approach on unicode (incrementing through every character) you'd be waiting a long time; there are millions of unicode characters.
To implement your original function (print the counts of each letter in alphabetical order) in terms of this:
def alphCount(text):
for character, count in sorted(letterOccurrances(text).iteritems()):
print "%s: %s" % (character, count)
alphCount("hello, world!")
the question is how to make
allTheLetters equal to said letters
without something like allTheLetters =
"abcdefg...xyz"
That's actually provided by the string module, it's not like you have to manually type it yourself ;)
import string
allTheLetters = string.ascii_lowercase
def alphCount(text):
lowerText = text.lower()
for letter in allTheLetters:
print letter + ":", lowertext.count(letter)
If you just want to do a frequency count of a string, try this:
s = 'hi there'
f = {}
for c in s:
f[c] = f.get(c, 0) + 1
print f
For counting objects, the obvious solution is the Counter
from collections import Counter
import string
c = Counter()
for letter in text.lower():
c[letter] += 1
for letter in string.lowercase:
print("%s: %d" % (letter, c[letter]))
Do you mean using:
import string
string.ascii_lowercase
then,
counters = dict()
for letter in string.ascii_lowercase:
counters[letter] = lowertext.count(letter)
All lowercase letters are accounted for, missing counters will have zero value.
using generators:
counters =
dict( (letter,lowertext.count(letter)) for letter in string.ascii_lowercase )
Something like this?
for letter in range(ord('a'), ord('z') + 1):
print chr(letter) + ":", lowertext.count(chr(letter))
Main question is "iterate through the alphabet":
import string
for c in string.lowercase:
print c
How get letter frequencies with some efficiency and without counting non-letter characters:
import string
sample = "Hello there, this is a test!"
letter_freq = dict((c,0) for c in string.lowercase)
for c in [c for c in sample.lower() if c.isalpha()]:
letter_freq[c] += 1
print letter_freq
How about this, to use letters, figures and punctuation (all usable to form a Django key):
import random
import string
chars = string.letters + string.digits + string.punctuation
chars_len = len(chars)
n = 40
print(''.join([chars[random.randint(0, chars_len)] for i in range(n)]))
Example result: coOL:V!D+P,&S*hzbO{a0_6]2!{4|OIbVuAbq0:
Just use:
import string
string.lowercase
string.uppercase
or
string.letters[:26]
string.letters[26:]
This is what I do:
import string
for x in list(string.lowercase):
print x