Converting mobile numeric keypad numbers to its corresponding word Python
Question:
I need to create a function, where, If I give an input like 999933. It should give output as “ze”. It basically work as numeric mobile phone keypad. How can I this. I have searched to get some sample in internet. All, I got was quite opposite. Like, Giving the text as input and you will get the number. I couldn’t get the exact flow of, how to achieve that. Please let me know, how can i do that.
def number_to_text(val):
pass
Answers:
Create a mapping pad_number to letter.
Use itertools.groupby
to iterate over consecutive pad presses and calculate which letter we get.
import itertools
letters_by_pad_number = {"3": "def", "9": "wxyz"}
def number_to_text(val):
message = ""
# change val to string, so we can iterate over digits
digits = str(val)
# group consecutive numbers: itertools.groupby("2244") -> ('2', '22'), ('4','44')
for digit, group in itertools.groupby(digits):
# get the pad letters, i.e. "def" for "3" pad
letters = letters_by_pad_number[digit]
# get how many consecutive times it was pressed
presses_number = len(list(group))
# calculate the index of the letter cycling through if we pressed
# more that 3 times
letter_index = (presses_number - 1) % len(letters)
message += letters[letter_index]
return message
print(number_to_text(999933))
# ze
And hardcore one-liner just for fun:
letters = {"3": "def", "9": "wxyz"}
def number_to_text(val):
return "".join([letters[d][(len(list(g)) - 1) % len(letters[d])] for d, g in itertools.groupby(str(val))])
print(number_to_text(999933))
# ze
You need to
- group the same digits together with the regex
(d)1*
that capture a digit then the same digit X times
- use the value of a digit in the group to get the key
- use the length of it to get the letter
phone_letters = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
def number_to_text(val):
groups = [match.group() for match in re.finditer(r'(d)1*', val)]
result = ""
for group in groups:
keynumber = int(group[0])
count = len(group)
result += phone_letters[keynumber][count - 1]
return result
print(number_to_text("999933")) # ze
Using list comprehension
def number_to_text(val):
groups = [match.group() for match in re.finditer(r'(d)1*', val)]
return "".join(phone_letters[int(group[0])][len(group) - 1] for group in groups)
The other answers are correct, but I tried to write a less brief more real world (including doctests) explanation of how the previous results worked:
dialpad_text.py
:
# Import the groupby function from itertools,
# this takes any sequence and returns an array of groups by some key
from itertools import groupby
# Use a dictionary as a lookup table
dailpad = {
'2': ['a', 'b', 'c'],
'3': ['d', 'e', 'f'],
'4': ['g', 'h', 'i'],
'5': ['j', 'k', 'l'],
'6': ['m', 'n', 'o'],
'7': ['p', 'q', 'r', 's'],
'8': ['t', 'u', 'v'],
'9': ['w', 'x', 'y', 'z'],
}
def dialpad_text(numbers):
"""
Takes in either a number or a string of numbers and creates
a string of characters just like a nokia without T9 support
Default usage:
>>> dialpad_text(2555222)
'alc'
Handle string inputs:
>>> dialpad_text('2555222')
'alc'
Handle wrapped groups:
>>> dialpad_text(2222555222)
'alc'
Throw an error if an invalid input is given
>>> dialpad_text('1BROKEN')
Traceback (most recent call last):
...
ValueError: Unrecognized input "1"
"""
# Convert to string if given a number
if type(numbers) == int:
numbers = str(numbers)
# Create our string output for the dialed numbers
output = ''
# Group each set of numbers in the order
# they appear and iterate over the groups.
# (eg. 222556 will result in [(2, [2, 2, 2]), (5, [5, 5]), (6, [6])])
# We can use the second element of each tuple to find
# our index into the dictionary at the given number!
for number, letters in groupby(numbers):
# Convert the groupby group generator into a list and
# get the offset into our array at the specified key
offset = len(list(letters)) - 1
# Check if the number is a valid dialpad key (eg. 1 for example isn't)
if number in dailpad.keys():
# Add the character to our output string and wrap
# if the number is greater than the length of the character list
output += dailpad[number][offset % len(dailpad[number])]
else:
raise ValueError(f'Unrecognized input "{number}"')
return output
Hope this helps you understand what’s going on a lower level! Also if you don’t trust my code, just save that to a file and run python -m doctest dialpad_text.py
and it will pass the doctests from the module.
(Notes: without the -v flag it won’t output anything, silence is golden!)
A slightly Modified answer of RaFalS without using itertools
import itertools
from collections import defaultdict
letters_by_pad_number = {"3": "def", "9": "wxyz"}
val = 999933
message = ""
digits = str(val)
num_group = defaultdict(int)
for digit in digits:
num_group[digit] += 1
for num in num_group.keys():
message += letters_by_pad_number[num][num_group[num]-1]
print(message)
# ze
I need to create a function, where, If I give an input like 999933. It should give output as “ze”. It basically work as numeric mobile phone keypad. How can I this. I have searched to get some sample in internet. All, I got was quite opposite. Like, Giving the text as input and you will get the number. I couldn’t get the exact flow of, how to achieve that. Please let me know, how can i do that.
def number_to_text(val):
pass
Create a mapping pad_number to letter.
Use itertools.groupby
to iterate over consecutive pad presses and calculate which letter we get.
import itertools
letters_by_pad_number = {"3": "def", "9": "wxyz"}
def number_to_text(val):
message = ""
# change val to string, so we can iterate over digits
digits = str(val)
# group consecutive numbers: itertools.groupby("2244") -> ('2', '22'), ('4','44')
for digit, group in itertools.groupby(digits):
# get the pad letters, i.e. "def" for "3" pad
letters = letters_by_pad_number[digit]
# get how many consecutive times it was pressed
presses_number = len(list(group))
# calculate the index of the letter cycling through if we pressed
# more that 3 times
letter_index = (presses_number - 1) % len(letters)
message += letters[letter_index]
return message
print(number_to_text(999933))
# ze
And hardcore one-liner just for fun:
letters = {"3": "def", "9": "wxyz"}
def number_to_text(val):
return "".join([letters[d][(len(list(g)) - 1) % len(letters[d])] for d, g in itertools.groupby(str(val))])
print(number_to_text(999933))
# ze
You need to
- group the same digits together with the regex
(d)1*
that capture a digit then the same digit X times - use the value of a digit in the group to get the key
- use the length of it to get the letter
phone_letters = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
def number_to_text(val):
groups = [match.group() for match in re.finditer(r'(d)1*', val)]
result = ""
for group in groups:
keynumber = int(group[0])
count = len(group)
result += phone_letters[keynumber][count - 1]
return result
print(number_to_text("999933")) # ze
Using list comprehension
def number_to_text(val):
groups = [match.group() for match in re.finditer(r'(d)1*', val)]
return "".join(phone_letters[int(group[0])][len(group) - 1] for group in groups)
The other answers are correct, but I tried to write a less brief more real world (including doctests) explanation of how the previous results worked:
dialpad_text.py
:
# Import the groupby function from itertools,
# this takes any sequence and returns an array of groups by some key
from itertools import groupby
# Use a dictionary as a lookup table
dailpad = {
'2': ['a', 'b', 'c'],
'3': ['d', 'e', 'f'],
'4': ['g', 'h', 'i'],
'5': ['j', 'k', 'l'],
'6': ['m', 'n', 'o'],
'7': ['p', 'q', 'r', 's'],
'8': ['t', 'u', 'v'],
'9': ['w', 'x', 'y', 'z'],
}
def dialpad_text(numbers):
"""
Takes in either a number or a string of numbers and creates
a string of characters just like a nokia without T9 support
Default usage:
>>> dialpad_text(2555222)
'alc'
Handle string inputs:
>>> dialpad_text('2555222')
'alc'
Handle wrapped groups:
>>> dialpad_text(2222555222)
'alc'
Throw an error if an invalid input is given
>>> dialpad_text('1BROKEN')
Traceback (most recent call last):
...
ValueError: Unrecognized input "1"
"""
# Convert to string if given a number
if type(numbers) == int:
numbers = str(numbers)
# Create our string output for the dialed numbers
output = ''
# Group each set of numbers in the order
# they appear and iterate over the groups.
# (eg. 222556 will result in [(2, [2, 2, 2]), (5, [5, 5]), (6, [6])])
# We can use the second element of each tuple to find
# our index into the dictionary at the given number!
for number, letters in groupby(numbers):
# Convert the groupby group generator into a list and
# get the offset into our array at the specified key
offset = len(list(letters)) - 1
# Check if the number is a valid dialpad key (eg. 1 for example isn't)
if number in dailpad.keys():
# Add the character to our output string and wrap
# if the number is greater than the length of the character list
output += dailpad[number][offset % len(dailpad[number])]
else:
raise ValueError(f'Unrecognized input "{number}"')
return output
Hope this helps you understand what’s going on a lower level! Also if you don’t trust my code, just save that to a file and run python -m doctest dialpad_text.py
and it will pass the doctests from the module.
(Notes: without the -v flag it won’t output anything, silence is golden!)
A slightly Modified answer of RaFalS without using itertools
import itertools
from collections import defaultdict
letters_by_pad_number = {"3": "def", "9": "wxyz"}
val = 999933
message = ""
digits = str(val)
num_group = defaultdict(int)
for digit in digits:
num_group[digit] += 1
for num in num_group.keys():
message += letters_by_pad_number[num][num_group[num]-1]
print(message)
# ze