Reputation: 29867
Is there a shorter way in Kotlin to write the following code:
private fun getMonth(monthText: String): Int {
var x = arrayOf("january", "february", "jumper").indexOf(monthText)
if (x >= 0)
return x
x = arrayOf("Januari", "Februari", "Maret").indexOf(monthText)
if (x >= 0)
return x
throw Exception("Not found")
}
I have to repeat the array search for many languages and want to avoid having to repeat duplicate code. Note: The returned value must indicate the month.
Upvotes: 0
Views: 179
Reputation: 2397
I would do it like this:
private fun getMonth(monthText: String): Int {
val a = arrayOf("january", "february", "jumper")
val b = arrayOf("Januari", "Februari", "Maret")
val result = a.zip(b)
.mapIndexed{idx, it -> if (it.first == monthText || it.second == monthText) idx else null }
.mapNotNull{it}.firstOrNull()
return result ?: throw Exception("Not found")
}
Upvotes: 0
Reputation: 29867
I think something like this would work (Note: For brevity I only listed 3 months for 2 languages. There are in fact 12 months for multiple languages):
private fun getMonth(monthText: String): Int {
var x = arrayOf("january", "february", "march", "jumper", "Januari", "Februari", "Maret").indexOf(monthText)
if (x < 0)
throw Exception("Month not found")
return (x % 12) + 1
}
Upvotes: 0
Reputation: 23242
I would probably hold some lists (or maps) containing your month texts and iterate over them, e.g.:
val englishMonths = sequenceOf("January", "February", "March" /*, ... */).mapIndexed { index, s -> s to index }.toMap()
val xxxMonths = sequenceOf("january", "february", "jumper"/*, ... */).mapIndexed { index, s -> s to index }.toMap()
// and all the other month mappings you need
Maybe you want to put those in an appropriate locale-mapping as well.
And your actual function would then just iterate over them:
fun getMonth(monthText : String) = sequenceOf(
// all the month lists that are relevant:
englishMonths, xxxMonths /*, ... */
)
.mapNotNull { it[monthText] }
.firstOrNull()
Which now would return null
if no match was found. You can also just add ?: throw WhateverExceptionSuites()
if you do not like a nullable type there.
Upvotes: 0
Reputation: 164054
With an array of arrays:
private fun getMonth(monthText: String): Int {
val array = arrayOf(
arrayOf("january", "february", "jumper"),
arrayOf("Januari", "Februari", "Maret")
)
val months = array.firstOrNull { it.contains(monthText) }
if (months != null) return months.indexOf(monthText)
throw Exception("Not found")
}
The only inefficiency of this I can think of is that the array where monthText
will be found, is scanned twice: once with contains()
and then with indexOf()
.
Upvotes: 0
Reputation: 662
Maybe not the nicest way:
I first build a set with all possible mappings of month to index. I define the lists and process them with mapIndexed
to get the index value. Afterwards I flatten those to get a set with Pair<String, Int>
val monthsToIndex by lazy {
val lists = listOf(
arrayOf("january", "february", "jumper"),
arrayOf("Januari", "Februari", "Maret")
);
lists.map { it.mapIndexed { i, s -> s to i } }.flatten().toSet()
};
The Search is now a find
in that set + a null check to throw the exception:
private fun getMonth(monthText: String): Int {
return monthsToIndex.find { it.first == monthText }?.second ?: throw Exception("Not found")
}
A benefit of that approach would be a very concise place where you initialise all values - and only once.
Update:
You can also convert this into a map as Frank Neblung has suggested - this would definitely speed up the search:
val monthsToIndex by lazy {
val lists = listOf(
arrayOf("january", "february", "jumper"),
arrayOf("Januari", "Februari", "Maret")
);
lists.map { it.mapIndexed { i, s -> s to i } }.flatten().toMap()
};
private fun getMonth(monthText: String): Int {
return monthsToIndex[monthText] ?: throw Exception("Not found")
}
Upvotes: 1
Reputation: 3165
For performance reasons, you should better hash than search
private val monthByName = mapOf(
"january" to 0,
"february" to 1,
"jumper" to 2,
"Januari" to 0,
"Februari" to 1,
"Maret" to 2
)
private fun getMonth(monthText: String) = monthByName[monthText] ?: throw NoSuchElementException(monthText)
Upvotes: 4