Python Forum
Explaining "translate" method
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Explaining "translate" method
#1
Hello,

I am working through some textbook exercises and was given the task:

Write a program that allows a user to type in a phrase and provides the acronym as the output. The acronym should be in uppercase.

I was able to solve it using two different approaches. The first solution works great and was my attempt after deleting everything and coming back to it fresh on the second day.

The second solution works but I stole code from Stack Overflow and don't fully understand it. Specifically, the last line which is using the translate method. Could someone help me digest this method?

Is it somehow looping through the letterString, looking at each character (ord) in the string and returning a 'none' value (i.e. blank) for any of those characters I selected?

Changing the code to add in "bacon" swaps out those characters for bacon.
print(letterString.translate({ord(i): "bacon" for i in " ',"}))
So, where I am struggling is around the syntax
{ord(i): blah blah} 
How does this syntax know to loop through each character in the string?

I know the second solution is ugly but wanted to learn from it anyway. It hasn't 'clicked' so hoping someone can help me think about it another way.

Thanks so much!


#Allows user to enter a string
phrase = str(input("Enter your phrase: "))

#Splits the string by each space (word)
#Note: after using a split, this sets the variable type to LIST!
split_phrase = phrase.split()

#Set an empty string to contain the acronym
acronym = str("")

#Loop through the items in the LIST of split_phrase
#Take the first element, set it as upper case
#Add it into the acronym variable
for i in split_phrase:
    first_letter = i[0].upper()
    acronym = acronym + first_letter

print("acronym is: " + acronym)
#User enters the string
#Split function divides it based on space
user_input = str(input("Please enter your phrase: ")).split()

#Creates a list.
#Loops through each item (word) in the user_input string. For the 0 index (first character) of each word. Assigns to list 
firstList = [x[0] for x in user_input]

#Creates a new list
#For each item in the list, change it to upper and assign it to the variable
secondList = [element.upper() for element in firstList]

#Creates a string from the list
letterString = str(secondList)

print(letterString.translate({ord(i): None for i in " ',"}))
Reply
#2
(Jan-11-2020, 07:45 AM)lummers Wrote: Write a program that allows a user to type in a phrase and provides the acronym as the output. The acronym should be in uppercase.

Like this?

Quote:How it supposed to work? --> HISTW

Task in spoken language: 'take first letter and make it uppercase for every word in sentence and join them into new string'

In [1]: s = 'How it supposed to work?'                                    

In [2]: ''.join([word[0].upper() for word in s.split()])                  
Out[2]: 'HISTW'
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#3
I think the documentation of str.translate() explains it very well. The way the dict is built may puzzle you but it's not very difficult
>>> {k: 'spam' for k in 'abc'}
{'a': 'spam', 'b': 'spam', 'c': 'spam'}
Reply
#4
(Jan-11-2020, 07:45 AM)lummers Wrote:
print(letterString.translate({ord(i): "bacon" for i in " ',"}))

The argument to translate is a dictionary and is produced by an expression called a dictionary comprehension. Python has comprehensions for other collections too (namely for sets and lists) and a related concept known as generator expressions. I'm giving you the names of these things so you can go and find out more about them.

Did you also try looking up the documentation for the ord and translate functions?
Reply
#5
If it's about string method translate maybe following examples can help to understand.

Task: we want to remove numbers from string using translate method

We create dictionary to replace numbers (by mapping numbers to None) and try to use translate:

>>> dict.fromkeys('0123456789')
{'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, '9': None}
>>> '2 for 1'.translate(dict.fromkeys('0123456789'))
'2 for 1'
Nothing happened. Why? .translate expects Unicode code points (integers) as keys.

If we use maketrans mentioned in documentation:

>>> remove_numbers = str.maketrans(dict.fromkeys('0123456789'))
>>> remove_numbers
{48: None, 49: None, 50: None, 51: None, 52: None, 53: None, 54: None, 55: None, 56: None, 57: None}
We see that it automagically replaced strings with Unicode code points. If we try translate with this we see expected result:

>>> '2 for 1'.translate(remove_numbers)
' for '                                   # we observe spaces before and after 'for' as they were
>>> '2 for 1'.translate(remove_numbers).strip()
'for'                                     # we can strip spaces from beginning and end
We can make translation dictionary by ourselves, not using maketrans method (like in example #2). In spoken language: 'give me key as unicode code point for character and value as None for every character in string':

>>> {ord(i): None for i in " ',"}
{32: None, 39: None, 44: None}
>>> {ord(i): None for i in '0123456789'}
{48: None, 49: None, 50: None, 51: None, 52: None, 53: None, 54: None, 55: None, 56: None, 57: None}
>>> '2 for 1'.translate({ord(i): None for i in '0123456789'})
' for '
If one is sufficiently proficient in Unicode then translation dictionary can be created like:

>>> {i: None for i in range(48,58)}
{48: None, 49: None, 50: None, 51: None, 52: None, 53: None, 54: None, 55: None, 56: None, 57: None}
>>> dict.fromkeys(range(48,58))
{48: None, 49: None, 50: None, 51: None, 52: None, 53: None, 54: None, 55: None, 56: None, 57: None}
Removing characters can be combined with replacing as well:

>>> mapping = str.maketrans({**dict.fromkeys('0123456789'), **{'f': 'F'}}) 
>>> mapping
{48: None, 49: None, 50: None, 51: None, 52: None, 53: None, 54: None, 55: None, 56: None, 57: None, 102: 'F'}
>>> '2 for 1'.translate(mapping)
' For '
Or only replacing (one can replace characters with word):

>>> nums_to_words = str.maketrans(dict(zip('0123456789', 'zero one two three four five six seven eight nine'.split())))
>>> nums_to_words
{48: 'zero', 49: 'one', 50: 'two', 51: 'three', 52: 'four', 53: 'five', 54: 'six', 55: 'seven', 56: 'eight', 57: 'nine'}
>>> '2 for 1'.translate(nums_to_words)                                    
'two for one'
You can translate one code point to string but not string (several code points) like '10' to some replacement value (like string ten):

>>> ord('10')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ord() expected a character, but string of length 2 found
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  for loop and if translate from R in Python Joey21 3 3,089 Feb-06-2018, 02:16 PM
Last Post: sparkz_alot
  Need help explaining what the variables do in my code. BurnedChipotle 6 4,828 Jan-30-2017, 10:48 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020