Kotlin custom high order functions
/**
* Apply filter and transform if element satisfy given condition
*
* @param condition to check
* @param transform to apply mapping
*/
inline fun <T, R : Any> Iterable<T>.mapFilterIf(
condition: (T) -> Boolean,
transform: (T) -> R
): List<R> {
return ArrayList<R>().let {
forEach { item ->
if (condition.invoke(item)) {
it.add(transform(item))
}
}
it
}
}
/**
* Apply transform if element satisfy given condition
*
* @param condition to check
* @param transform to apply mapping
*/
inline fun <T> Iterable<T>.mapIf(
condition: (T) -> Boolean,
transform: (T) -> T
): List<T> {
return ArrayList<T>().let {
forEach { item ->
if (condition.invoke(item)) {
it.add(transform(item))
} else {
it.add(item)
}
}
it
}
}
/**
* Pop random element from collection
*/
fun <T : Any> ArrayList<T>.popRandom(): T {
return this.random().also {
remove(it)
}
}
/**
* Pop element matched given condition
*
* @param condition to check
*/
inline fun <T : Any> ArrayList<T>.popIf(
condition: (T) -> Boolean
): T? {
return firstOrNull {
condition(it)
}.let {
remove(it)
return@let it
}
}
/**
* Run let block if condition matched
*/
inline fun <T, R> T.letIf(condition: (T) -> Boolean, block: (T) -> (R)): R? {
if (condition(this)) {
return let(block)
}
return null
}
/**
* Sort collection with given order(list)
*/
class SortingWithGivenOrder<T>(
private val selector: (T) -> String,
private val orders: List<String>
) : Comparator<T> {
constructor(selector: (T) -> String, vararg orders: String) : this(selector, orders.toList())
private val ordersMap = HashMap<String, Int>().apply {
orders.forEachIndexed { index, s -> put(s, index) }
}
override fun compare(one: T, two: T): Int {
return ordersMap.getOrElse(selector(one), { ordersMap.size }) - ordersMap.getOrElse(
selector(two), { ordersMap.size })
}
}
/**
* Try given code block with retry count, if it exceed limit, throw exception
*
* @throws [IllegalArgumentException] if given retry count < 1
*/
inline fun <T> retry(retryCount: Int, block: () -> T): T {
for (count in 1..retryCount) {
return try {
block()
} catch (e: Exception) {
Timber.w("Retry...($count)")
if (count == retryCount)
throw e
else
continue
}
}
throw IllegalArgumentException("Given retry count must be bigger than 0")
}
/**
* Get 00:00:00:0000 of day in millisecond
*/
fun Calendar.getDayStartMills(): Long =
this.apply {
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
/**
* Get 23:59:59:999 of day in millisecond
*/
fun Calendar.getDayEndMills(): Long =
this.apply {
set(Calendar.HOUR_OF_DAY, 23)
set(Calendar.MINUTE, 59)
set(Calendar.SECOND, 59)
set(Calendar.MILLISECOND, 999)
}.timeInMillis