I'm new to Scala and to Functional Programming. I'm busy rewriting a Python (procedural) module into a Scala Object Class. I'm stuck where I need to define a method (ExtractTime) that takes in a String and Map (Dictionary) as arguments and returns the result as a tuple based the val functions results within the method. I have three functions within the method that return "Hours", "Minutes", "Period". The error message that I've received is that the return type is "Unit" and the required output is (Int, Int, String). How can I return the values within the "ExtractTime" method as a tuple, note that the output types are not the same (i.e. Int, Int, String).
package Time
/**
* Created by PeterW on 6/11/2017.
*/
object TimeAsWords2 extends App {
// Input string argument is based on 24hr format 23:59
val InputTime = args(0)
// regular expression string
val Exp24hr = """^(([01]\d|2[0-3]):([0-5]\d)|23:59)$"""
// a Map of word equivalent of integer values
val WordsLookup = Map(1 -> "one", 2 -> "two", 3 -> "three", 4 -> "four",
5 -> "five", 6 -> "six", 7 -> "seven", 8 -> "eight",
9 -> "nine", 10 -> "ten", 11 -> "eleven", 12 -> "twelve",
13 -> "thirteen", 14 -> "fourteen", 16 -> "sixteen",
17 -> "seventeen", 18 -> "eighteen", 19 -> "nineteen",
20 -> "twenty", 21 -> "twenty one", 22 -> "twenty two",
23 -> "twenty three", 24 -> "twenty four", 25 -> "twenty five",
26 -> "twenty six", 27 -> "twenty seven", 28 -> "twenty eight",
29 -> "twenty nine")
// a Map of time periods
val PeriodLookup = Map(1 -> "before midday", 2 -> "after midday")
// main method to covert time in 24hr format to time as words
def TimeAsWords(InputTime: String, Exp24hr: String,
WordsLookup: Map[Int, String], PeriodLookup: Map[Int, String]) = {
def ExtractTime(InputTime: String, PeriodLookup: Map[Int, String]) : (Int, Int, String) = {
// extract hours from string
val HrsInt = InputTime.take(2).toInt
// convert HrsInt into 12hrs using (12 - ((HrsInt) % 12)
val Hrs12Int = 12
// extract minutes from string
val MinInt = InputTime.takeRight(2).toInt
// determine PdString (PeriodLookup(2) if HrsInt >= 12 else PeriodLookup(1))
val PdString = PeriodLookup(1).mkString
def ConvertTime(Hrs12Int: Int, MinInt: Int, PrString: String) = {
// convert input hours, minutes and period into time as words
// based on if else if conditions based on Python module
// return time as words as a string
}
// test if input time matches 24hr format else stop program
// and return message that format is incorrect
val pattern24hr = InputTime.matches(Exp24hr)
if (InputTime.matches(Exp24hr)){
val (Hrs12Int, MinInt, PdString) = ExtractTime(InputTime, PeriodLookup)
val TimeWords = ConvertTime(Hrs12Int, MinInt, PdString)
println(TimeWords)
} else{
println("Input time format doesn't match 24hr format: 00:00 - 23:59")
System.exit(0)
}
}
}
TimeAsWords(InputTime, Exp24hr, WordsLookup, PeriodLookup)
}
Scala Object: TimeAsWords
Scala Method ExtractTime: Error Message
"""
Created on 28 May 2017
Convert 24hr format time
into time as words
@author: PeterW
"""
import sys
import re
import argparse
def words_lookup():
"""Create a dictionary
to lookup equivalent word
of integer number"""
words_dict = {1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five',
6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten',
11: 'eleven', 12: 'twelve', 13: 'thirteen',
14: 'fourteen', 16: 'sixteen', 17: 'seventeen',
18: 'eighteen', 19: 'nineteen', 20: 'twenty',
21: 'twenty one', 22: 'twenty two', 23: 'twenty three',
24: 'twenty four', 25: 'twenty five', 26: 'twenty six',
27: 'twenty seven', 28: 'twenty eight', 29: 'twenty nine'}
return words_dict
def validate_time_format(input_time):
"""Validate that input string
matches require 24hr time format"""
regexp_object = re.compile(r'^(([01]\d|2[0-3]):([0-5]\d)|23:59)$')
if regexp_object.match(input_time):
print("Processing: {0} into words".format(input_time))
time_str = input_time
else:
print("{0} doesn't match required input format: 00:00 to 23:59"
.format(input_time))
sys.exit()
return time_str
def extract_time(time_str):
"""Convert time from 24hr format
into 12hours, minutes and period"""
period_type = {'am': 'before midday', 'pm': 'after midday'}
try:
hours, minutes = int(time_str[:2]), int(time_str[3:])
suffix = "{0}".format("pm" if hours >= 12 else 'am')
hours = 12 - ((-hours) % 12)
period = period_type.get(suffix)
except ValueError as err:
print(err)
sys.exit()
return hours, minutes, period
def time_conversion(words_dict, hours, minutes, period):
"""Return time as words
based on relevant condition"""
if hours == 12:
hours2 = words_dict.get(1)
else:
hours2 = words_dict.get(hours+1)
if hours == 12 and minutes == 0 and period == 'before midday':
time_words = 'Midnight'
elif hours == 12 and minutes == 0 and period == 'after midday':
time_words = 'Midday'
elif minutes == 0:
time_words = "{0} o'clock {1}.".format(str(words_dict.get(hours)).title(),
period)
elif minutes == 15:
time_words = "Quarter past {0} {1}.".format(words_dict.get(hours),
period)
elif minutes == 30:
time_words = "Half past {0} {1}.".format(words_dict.get(hours),
period)
elif minutes == 45:
time_words = "Quarter to {0} {1}.".format(hours2,
period)
elif minutes < 30:
min_str = words_dict.get(minutes).capitalize()
min_num = "" if minutes == 1 else "s"
time_words = "{0} minute{1} past {2} {3}.".format(min_str,
min_num,
words_dict.get(hours),
period)
else:
min_str = words_dict.get(60 - minutes).capitalize()
min_num = "" if 60 - minutes == 1 else "s"
time_words = '{0} minute{1} to {2} {3}.'.format(min_str,
min_num,
hours2,
period)
return time_words
def time_as_words(input_time):
"""Convert 24hr format time
into time as words"""
words_dict = words_lookup()
time_str = validate_time_format(input_time)
hours, minutes, period = extract_time(time_str)
time_words = time_conversion(words_dict, hours, minutes, period)
print(time_words)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Convert 24hr format time into time as words")
parser.add_argument("-t", "--input_time", metavar="time", type=str, required=True,
help='input time in the following format 00:00 to 23:59')
args = parser.parse_args()
time_as_words(input_time=args.input_time)
Python Module: TimeAsWords
object session {
val PeriodLookup = Map(1 -> "before midday", 2 -> "after midday")
def ExtractTime(InputTime: String, PeriodLookup: Map[Int, String]): (Int, Int, String) = {
// extract hours from string
val HrsInt = InputTime.take(2).toInt
// convert HrsInt into 12hrs using (12 - ((HrsInt) % 12)
val Hrs12 = 12
// extract minutes from string
val MinInt= InputTime.takeRight(2).toInt
// determine PdString (PeriodLookup(2) if HrsInt >= 12 else PeriodLookup(1))
val PdString = PeriodLookup(1).mkString
new Tuple3(HrsInt, MinInt , PdString)
}
val (hours1, minutes1, period1) = ExtractTime("18:45", PeriodLookup)
println(hours1, minutes1, period1)
}
Updated Version: Scala Object ExtractTime Method
ExtractTime
to return a tuple(Int, Int, String)
but the method is not returning anything (Unit
). Make sure that the method actually returns a tuple, or declare the return type to beUnit
instead of(Int, Int, String)
. – JesperTimeAsWords
only contains the definition of a nested methodExtractTime
and nothing else. You'll need to add code to the method that actually does something, because just declaring a method doesn't do anything at runtime. – Jesper