Alex
03/31/2022, 10:40 AMAlex
03/31/2022, 10:42 AMa121_c312_t1231_dasdasdaada
and can may contain unnecessary “keys” like a8888
at the end so it’s important for the first keys to have precedenceFleshgrinder
03/31/2022, 10:43 AMval affiliateId: String?
init {
var affiliateId: String? = null
// snip
this.affiliateId = affiliateId
}
Alex
03/31/2022, 10:46 AMFleshgrinder
03/31/2022, 10:51 AMclass C(val a: String?, val b: String?, val c: String?) {
companion object {
operator fun invoke(a: String?): C {
var b: String? = null
var c: String? = null
// snip
return C(a, b, c)
}
}
}
This is useful for unit testing (object mothers), because now you can freely assign values to b
and c
without going through the init logic. Obviously the constructor can be internal
if you want to keep this possibly away from others.Alex
03/31/2022, 10:55 AMFleshgrinder
03/31/2022, 11:07 AMcompanion object {
@JvmStatic
@JsonCreator
operator fun invoke() {}
}
Alex
03/31/2022, 12:41 PMinit { }
actually won’t work and companion object
is the way to go. 😄Ivan Pavlov
04/01/2022, 8:22 AMfilter
you check both isNotEmpty
(length > 0) and substring(1).isNotEmpty()
(length > 1) which can be probably simplified with it.length
2. You reverse list and then iterate with forEach. In this forEach if you find prefix, you set corresponding variable. If you have multiple items with the same prefix you will override property. This means that the latest (in reversed list) set wins. And latest in reversed is the first in original.
If you put things together you can end up with something like this:
data class QTag(val rawQTag: String?) {
val affiliateId: String?
val creativeId: String?
val trackerId: String?
init {
// build intermediate list of strings to perform search later
val strs = rawQTag.orEmpty().lowercase()
.split("_")
.filter { it.length > 1 }
affiliateId = strs.findIdByPrefix("a")
creativeId = strs.findIdByPrefix("c")
trackerId = strs.findIdByPrefix("t")
}
private fun List<String>.findIdByPrefix(prefix: String): String? = firstNotNullOfOrNull {
if (it.substring(0, 1) == prefix) it.substring(1) else null
}
}
Tim Oltjenbruns
04/04/2022, 3:37 PMassociateBy
to output a map of items by prefix. Then afterwards assign the item by prefix into the appropriate variables.Tim Oltjenbruns
04/04/2022, 3:55 PMdata class QTag(val rawQTag: String?) {
val affiliateId: String?
val creativeId: String?
val trackerId: String?
init {
// build intermediate list of strings to perform search later
val substringsByPrefix = rawQTag.orEmpty().lowercase()
.split("_")
.filter { it.length > 1 }
.reversed()
.associateBy { it[0] }
affiliateId = substringsByPrefix.getWithoutPrefix('a')
creativeId = substringsByPrefix.getWithoutPrefix('c')
trackerId = substringsByPrefix.getWithoutPrefix('t')
}
private fun Map<Char, String>.getWithoutPrefix(c: Char) = this[c]?.substring(1)
}
The firstOfNotNull works too. It seems a little less clear to me, but with the potential benefit of being more performant if you expect most cases to have way more substrings than you are parsing.
If you expect the typical case to include exactly these substrings and no more, then the potential benefit of the firstNotNullOfOrNull
approach does not apply.Fleshgrinder
04/04/2022, 4:12 PMsplit("_")
already results in an additional list allocation, all additional operations like substring and associate also result in additional allocations. If raw speed matters than nothing like this should be done, and instead the string should be parsed.