I'm absolutely terrible at Python and my Computer Programming class ends in two days (thank god), but I am having the hardest time figuring out what is probably the easiest code ever.
The instructions to my assignment state, "Write a program which reads in text until a '!' is found. Use an array of integers subscripted by the letters 'A' through 'Z'."
From what i have done so far:
msg = input("What is your message? ")
msg = msg.upper()
int_array = [0] * 26
for alph in range (65, 91):
char = chr(alph)
print(char)
(int_array[char])
any help would be greatly appreciated! thanks!
EDIT: This is the full assignment:
Write a program which reads in text from the keyboard until a ('!') is found.
Using an array of integers subscripted by the letters 'A' through 'Z', count the number occurrences of each letter (regardless of whether it is upper or lower case). In a separate counter, also count the total number of "other" characters ('.', '?', ' ', '2', etc.).
Print out the count for each letter found. Also, print the count of the non-letter characters.
By inspecting the array, print out the count of the number of vowels, and the number of consonants.
Print out which letter was found the most times. (Note there may be more than one letter which has the maximum count attached to it.) Print out which letter (or letters) was found the least number of times, but make certain to exclude letters which were not found at all.
UPDATE:
I have gotten this far with my code
msg = input("What is your message? ")
print ()
num_alpha = 26
int_array = [0] * num_alpha
for alpha in range(num_alpha):
int_array[alpha] = chr(alpha + 65)
print(int_array[alpha], end = "")
print()
lett = 0
otherch = 0
num_vowels = 0
num_consanants = 0
count_character = [0] * 100000
length = len(msg)
for character in msg.upper():
if character == "!":
print("lett =", lett)
print("other char = ", otherch)
print("num_vowels = ", num_vowels)
print("num_consanants = ", num_consanants)
elif character < "A" or letter > "Z":
otherch = otherch + 1
count_character[ord(character)] = count_character[ord(character)] + 1
else:
lett = lett + 1
count_character[ord(character)] = count_character[ord(character)] + 1
for character in msg:
print("character", character, "appeared" , count_character[ord(character)] , "times")
it's obviously not finished yet, but every time i print the last print statement, it says that each character appeared 0 times. can anybody help?
You're going to need to get clarification on this, because there's no such thing as "an array of integers subscripted by the letters 'A' through 'Z'" in Python.
Possible interpretations that I can think of:
It's supposed to be a dictionary rather than an array. Python dictionaries are similar to lists (the Python datatype that is roughly equivalent to "arrays" in other languages), but they can be subscripted by strings, whereas lists can be subscripted only by integers. This way, you can store an integer to be associated with each letter. This is how most Python programmers would generally do something like this.
You're supposed to use parallel lists. You can do this by making two lists of 26 elements each, one containing the letters 'A' through 'Z' and one containing integers. For each letter, you could then use the list.index method to find the index in the first list where that letter is, then look up that index in the second list. (In theory, you wouldn't really need the first list, since Python strings are like lists in that they can be subscripted with integers and support the index method. So you could use the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' instead of a list. Or you could use the ord function, which is the inverse of the chr function. But I don't know if you're supposed to use these features.)
I'm not 100% sure the following is right because I agree with the others that the assignment description is wonky. It looks like a C-based homework assignment lazily ported to Python. That said:
In principle rather than hardcoding the bounds of the alphabet I'd go with ord('A') and ord('Z')+1, so that I can say something like alphabet = list(range(ord('A'), ord('Z')+1))
Renaming int_array to counter might make it more obvious what you need to do in your inner loop (keeping in mind that you're using the letters as your indices. Or rather, you'd need something more like ord(letter)-ord('A') as your indices)
You don't want to loop over the alphabet; you want to loop over the input.
count should be initialized to [0]*27 to track "other" values. You can increment counter[-1] for non-alphabetic characters.
Your final value is chr of counter.index(max(counter)). You may find it more straightforward, or your teacher may find it more acceptable, to just write a for loop.
Related
I'm trying to print the "least" character in a string, where the a character is smaller if it's closer to the beginning of the alphabet than another character, and it's first index position.
I'm supposed to use only 1 loop to determine the index of the character, and am not allowed to use min, max, index, find, ord, chr, or lists.
For example:
leastChar("yRrcDefxBqubSlyjYelskd")
should yield:
The least char is 'B' and occurs at position 8.
Currently I have:
def leastChar(inputString):
lowerString = inputString.lower()
print(lowerString)
indexLength = (len(lowerString) - 1)
print(indexLength)
index = 0
for i in range(indexLength):
if lowerString[i] < lowerString[i+1]:
index = i
print("The least char is '{0}' and occurs at position {1}".format(inputString[index], index))
Which returns:
leastChar("yRrcDefxBqubSlyjYelskd")
yrrcdefxbqubslyjyelskd
21
The least char is 'l' and occurs at position 18
I've tried multiple variations, but even using more than 1 loop I find myself getting consistently wrong answers in various positions.
Also, in case it matters, leastChar('blAh') will return 'A' in position 2 like it's supposed to.
The closest I've come to what seems correct, I think, is when I put another for loop inside the initial for loop hoping that I could increment that variable to compare 'i' to it such as:
for i in range(indexLength):
for j in range(indexLength):
if lowerString[i] < lowerString[j]:
And do something with that, but I was unable to make it work.
Thanks for the help.
Expanding on #melpomeneās comment, the algorithm trick (or as fancy computer scientists call it, heuristic) is to keep track of both the minimum position and minimum value as you are iterating through the string.
def leastChar(inputString):
# handle cases where inputString is `None` or empty
if not inputString:
print('Oh no, inputString is blank! Run away!')
return
lowerString = inputString.lower()
print(lowerString)
# use enumerate to keep track of the index as
# you are iterating over a list
min_value = lowerString[0]
min_pos = 1
for index, ch in enumerate(lowerString, 1):
# check to see if current char is closer to
# front of alphabet than our current minimum
if ch < min_value:
# if so, keep track of the current pos/value
# as the new minimum
min_pos = index
min_value = ch
# pythonic: min_pos, min_value = index, ch
print("The least char is '{0}' and occurs at position {1}".format(min_value, min_pos))
There are different ways:
1) You're not allowed to use min, max, index, find, ord, chr, or lists?
I would try to work with rfind() or rindex(). :^)
2) Copy your string and use sort() to find the smallest char in your copy. Then you should use search() to return the position of this char in your original InputString.
3) Create an alphabetic string "abcdef...." and build up a complex while-if-try-except construct to get a result, but everyone would hate it. :^)
For a school project I have to create a function called find_str that essentially does the same thing as the .find string method, but we cannot use any string methods in our definition.
The project description reads: "Function find_str has two parameters (both strings). It returns the lowest index where the second parameter is found within the first parameter (it returns -1 if the second parameter is not found within the first parameter)."
I have spent a lot of time working on this project and have yet to come to a solution. This is the current definition that I have come up with:
def find_str (string, substring):
index = 0
length = len (substring)
for ch in string:
if ch == substring [0]:
subindex1 = 0
subindex2 = index
for i in range (length):
if ch == substring [i]:
subindex1 +=1
if subindex1 == length:
return index
ch = string [(subindex2)+1]
subindex2 +=1
index += 1
return "-1"
This sample of code only works in some instances, but not all.
For example:
print (find_str ("hello", "llo"))
returns:
2
as it should.
But
print (find_str ("hello", "el"))
returns:
ch = string [(subindex2)+1]
IndexError: string index out of range
I feel like I am overthinking this and there must be is an easier way to do it. Any input or help would be great! Thanks.
FFUsing a sub function to clear your thoughts often help.
def find_str (string, substring):
index = 0
length = len (substring)
for j in range(len(string)):
if is_next_sub(string, substring, j):
return j
return "-1"
def is_next_sub(string, substring, index):
for i in range(len(substring)):
if substring[i] != string[index + i]:
return False
return True
I'm not sure we should be helping you with 'homework'
How about this:
def find_str(string, substring):
for off in xrange(len(string)):
if string[off:].startswith(substring):
return off
return -1
I haven't checked through your code in detail, but it looks like you're trying to compare characters that don't exist.
Suppose you're searching "aaaaa" for the substring "aaa", and you need to find all matches...
String : aaaaa
Match at 0 : aaa..
Match at 1 : .aaa.
Match at 2 : ..aaa
Even though the characters always match, and there five characters in the string, there are only three positions that you might need to consider.
So before you look at the actual characters at all, you can restrict the number of start positions you might need to consider based on the lengths of the string and substring. You only loop for those start positions. That means you're not looping for start positions that cannot match. Also, if you don't do this...
String : aaaaa
Match at 0 : aaa..
Match at 1 : .aaa.
Match at 2 : ..aaa
Match at 3 : ...aa!
Match at 4 : ....a!!
Those exclamation points are places where you try to match a character in the substring with a character that doesn't exist, after the end of the string. You can check for that within the loop to avoid the error each time it occurs, but why not eliminate all those cases at once by not looping for the match positions that cannot occur?
The number of start positions you may need to check is len(fullstring) + 1 - len(substring), so you can derive a range of possible start positions using range(0, len(fullstring) + 1 - len(substring)).
I am trying to shift the letters of a string over by 1 each time a while loop runs(so "A" becomes "B", "B" becomes "C" and so on each time through).
I need to have each result displayed so I can compare them. What I don't want to do but know how to do is create 26 different functions each one shifting the letters one letter farther but this seems a bit ridiculous.
How do I assign a variable to ttk each time the while loop goes through?
I thought this would assign "ls" plus whatever the count was on (ls1, ls2, ls3...) to each variable but it does not. It throws an error every time.
def shift1(*args):
s = code.get()
storage = []
count = 1
while (count <= 26):
l = [ord(i) for i in s]
sh = ([chr(i + count) for i in l])
storage.append(sh)
("ls"+str(count)).set(storage(count - 1))
count += 1
It give me an error that says
AttributeError: 'str' object has no attribute 'set'
Like I said I could just use this function 26 times each time assigning a diff ttk variable.
def shift1(*args):
s = code.get()
l = [ord(i) for i in s]
sh1.set(''.join([chr(i + 1) for i in l]))
This will essentially bypass the loop, but I know there has to be a better way.
Very new to python and ttk so any help is appreciated.
You don't need to use a while loop, you can just iterate using a for loop instead. As with Bemmu's answer this forces the characters to be all upper case, as it makes it easier. But you can modified a little more so it checks based on upper or lower case characters.
def shift(str):
str =str.upper()
for i in range(26):
print "".join([chr((ord(x)-65+i)%26+65) for x in str])
shift("hello")
You can see this in operation here: http://codepad.org/OaBXM4s2
Here is a way to rotate the characters in a string around, assuming there are only A-Z letters in your string.
string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i in range(10):
string = "".join([chr((ord(letter) - ord('A') + 1) % 26 + ord('A')) for letter in string])
print string
The idea is that each letter has an ASCII code difference from the letter A. So letter A would be 0, letter B is 1. When letter Z is shifted forward, it needs to go back to A. This is where the modulo (%) comes in, it shifts the letter Z back to A if needed.
Output:
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
I have the following problem: I would like to write a function in Python which, given a string, returns a string where every group of two characters is swapped.
For example given "ABCDEF" it returns "BADCFE".
The length of the string would be guaranteed to be an even number.
Can you help me how to do it in Python?
To add another option:
>>> s = 'abcdefghijkl'
>>> ''.join([c[1] + c[0] for c in zip(s[::2], s[1::2])])
'badcfehgjilk'
import re
print re.sub(r'(.)(.)', r'\2\1', "ABCDEF")
from itertools import chain, izip_longest
''.join(chain.from_iterable(izip_longest(s[1::2], s[::2], fillvalue = '')))
You can also use islices instead of regular slices if you have very large strings or just want to avoid the copying.
Works for odd length strings even though that's not a requirement of the question.
While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.
It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.
Also added code to ensure string is of even length as it only works for even length.
string = "abcdefghijklmnopqrstuvwxyz123"
# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
string = string[:-1]
# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
swapped_pair += (string[i + 1] + string[i])
# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
swapped_adj += swapped_pair[-1]
print(swapped_pair)
badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used
Here's a nifty solution:
def swapem (s):
if len(s) < 2: return s
return "%s%s%s"%(s[1], s[0], swapem (s[2:]))
for str in ("", "a", "ab", "abcdefgh", "abcdefghi"):
print "[%s] -> [%s]"%(str, swapem (str))
though possibly not suitable for large strings :-)
Output is:
[] -> []
[a] -> [a]
[ab] -> [ba]
[abcdefgh] -> [badcfehg]
[abcdefghi] -> [badcfehgi]
If you prefer one-liners:
''.join(reduce(lambda x,y: x+y,[[s[1+(x<<1)],s[x<<1]] for x in range(0,len(s)>>1)]))
Here's a another simple solution:
"".join([(s[i:i+2])[::-1]for i in range(0,len(s),2)])
Input is a string, the idea is to count the letters A-z only, and print them alphabetically with the count of appearances.
As usual I kept at this 'till I got a working result, but now seek to optimize it in order to better understand the Python way of doing things.
def string_lower_as_list(string):
"""
>>> string_lower_as_list('a bC')
['a', ' ', 'b', 'c']
"""
return list(string.lower())
from sys import argv
letters = [letter for letter in string_lower_as_list(argv[1])
if ord(letter) < 124 and ord(letter) > 96]
uniques = sorted(set(letters))
for let in uniques:
print let, letters.count(let)
How do I remove the duplication of ord(letter) in the list comprehension?
Would there have been any benefit in using a Dictionary or Tuple in this instance, if so, how?
EDIT
Should have said, Python 2.7 on win32
You can compare letters directly and you actually only need to compare lower case letters
letters = [letter for letter in string_lower_as_list(argv[1])
if "a" <= letter <= "z"]
But better would be to use a dictionary to count the values. letters.count has to traverse the list every time you call it. But you are already traversing the list to filter out the right characters, so why not count them at the same time?
letters = {}
for letter in string_lower_as_list(argv[1]):
if "a" <= letter <= "z":
letters[letter] = letters.get(letter, 0) + 1
for letter in sorted(letters):
print letter, letters[letter]
Edit: As the others said, you don't have to convert the string to a list. You can iterate over it directly: for letter in argv[1].lower().
How do I remove the duplication of ord(letter) in the list comprehension?
You can use a very Python-specific and somewhat magical idiom that doesn't work in other languages: if 96 < ord(letter) < 124.
Would there have been any benefit in using a Dictionary or Tuple in this instance, if so, how?
You could try using the collections.Counter class added in Python 2.7.
P.S. You don't need to convert the string to a list in order to iterate over it in the list comprehension. Any iterable will work, and strings are iterable.
P.S. 2. To get the property 'this letter is alphabetic', instead of lowercasing and comparing to a range, just use str.isalpha. Unicode objects provide the same method, which allows the same code to Just Work with text in foreign languages, without having to know which characters are "letters". :)
You don't have to convert string to list, string is iterable:
letters = {}
for letter in argv[1].lower():
if "a" <= letter <= "z":
letters[letter] = letters.get(letter, 0) + 1
for letter in sorted(letters.keys()):
print letter, letters[letter]