Skip to content

Instantly share code, notes, and snippets.

@nicokosi
Last active July 27, 2020 06:00
Show Gist options
  • Save nicokosi/2cb6964e18b14b15a71ba4a493f64b61 to your computer and use it in GitHub Desktop.
Save nicokosi/2cb6964e18b14b15a71ba4a493f64b61 to your computer and use it in GitHub Desktop.
My answers to Kotlin Playground Koans: https://play.kotlinlang.org/koans
/* My answers to [Kotlin Playground Koans](https://play.kotlinlang.org/koans) */
/* Intro */
// Hello, world!
fun start(): String = "OK"
// Named arguments
fun joinOptions(options: Collection<String>) =
options.joinToString(prefix = "[", postfix = "]")
// Default arguments
fun foo(
name: String,
number: Int = 42,
toUpperCase: Boolean = false) =
(if (toUpperCase) name.toUpperCase() else name) + number
fun useFoo() = listOf(
foo("a"),
foo("b", number = 1),
foo("c", toUpperCase = true),
foo(name = "d", number = 2, toUpperCase = true))
// Lambdas
fun containsEven(collection: Collection<Int>): Boolean =
collection.any { it -> it % 2 == 0 }
// Strings
val month = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)"
fun getPattern(): String = """\d{2}\s${month}\s\d{4}"""
// Data classes
data class Person(private val name: String, private val age: Int)
fun getPeople(): List<Person> =
listOf(Person("Alice", 29), Person("Bob", 31))
// Nullable types
fun sendMessageToClient(
client: Client?, message: String?, mailer: Mailer) {
var email = client?.personalInfo?.email
if (email == null || message == null) return
return mailer.sendMessage(
client?.personalInfo?.email!!,
message)
}
// Smart casts
fun eval(expr: Expr): Int =
when (expr) {
is Num -> expr.value
is Sum -> eval(expr.left) + eval(expr.right)
else -> throw IllegalArgumentException("Unknown expression")
}
interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
// Extension functions
fun Int.r(): RationalNumber =
RationalNumber(toInt(), 1)
fun Pair<Int, Int>.r(): RationalNumber =
RationalNumber(first.toInt(), second.toInt())
data class RationalNumber(val numerator: Int, val denominator: Int)
// Object expressions
fun getList(): List<Int> {
val arrayList = arrayListOf(1, 5, 2)
java.util.Collections.sort(
arrayList,
object : Comparator<Int> {
override fun compare(a: Int, b: Int) = b - a
}
)
return arrayList
}
// Single Abstract Method conversions
fun getList(): List<Int> {
val arrayList = arrayListOf(1, 5, 2)
java.util.Collections.sort(arrayList, { x, y -> y - x })
return arrayList
}
// Extensions on collections
fun getList(): List<Int> = arrayListOf(1, 5, 2).sortedDescending()
/* My answers to [Kotlin Playground Koans](https://play.kotlinlang.org/koans) */
/* Conventions */
// Comparison
data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int)
: Comparable<MyDate> {
override fun compareTo(other: MyDate) =
year -other.year + month - other.month + dayOfMonth - other.dayOfMonth
}
fun compare(date1: MyDate, date2: MyDate) = date1 < date2
// In range
class DateRange(val start: MyDate, val endInclusive: MyDate) {
operator fun contains(date: MyDate) =
date.compareTo(start) > 0 && date.compareTo(endInclusive) < 0
}
fun checkInRange(date: MyDate, first: MyDate, last: MyDate)
= date in DateRange(first, last)
// Range to
operator fun MyDate.rangeTo(other: MyDate) = DateRange(this, other)
class DateRange(
override val start: MyDate,
override val endInclusive: MyDate): ClosedRange<MyDate>
fun checkInRange(date: MyDate, first: MyDate, last: MyDate) =
date in first..last
// For loop
class DateRange(val start: MyDate, val end: MyDate): Iterable<MyDate> {
override operator fun iterator(): Iterator<MyDate> {
return object: Iterator<MyDate> {
var currentDate = start
override fun hasNext(): Boolean {
return currentDate <= end
}
override fun next(): MyDate {
val now = currentDate
currentDate = currentDate.nextDay()
return now
}
}
}
}
fun iterateOverDateRange(firstDate: MyDate, secondDate: MyDate, handler: (MyDate) -> Unit) {
for (date in firstDate..secondDate) {
handler(date)
}
}
// Operators overloading
data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int)
enum class TimeInterval { DAY, WEEK, YEAR }
operator fun MyDate.plus(timeInterval: TimeInterval): MyDate =
this.addTimeIntervals(timeInterval, 1)
fun task1(today: MyDate): MyDate = today + YEAR + WEEK
operator fun TimeInterval.times(number: Int): TimeIntervals = TimeIntervals(number, this)
data class TimeIntervals(val number: Int, val timeInterval: TimeInterval)
operator fun MyDate.plus(timeIntervals: TimeIntervals): MyDate =
this.addTimeIntervals(timeIntervals.timeInterval, timeIntervals.number)
fun task2(today: MyDate): MyDate = today + YEAR * 2 + WEEK * 3 + DAY * 5
// Destructuring declarations
class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) {
operator fun component1() = year
operator fun component2() = month
operator fun component3() = dayOfMonth
}
fun isLeapDay(date: MyDate): Boolean {
val (year, month, dayOfMonth) = date
// 29 February of a leap year
return year % 4 == 0 && month == 2 && dayOfMonth == 29
}
// Invoke
class Invokable {
var numberOfInvocations: Int = 0
private set
operator fun invoke(): Invokable {
numberOfInvocations++
return this
}
}
fun invokeTwice(invokable: Invokable) = invokable()()
/* My answers to [Kotlin Playground Koans](https://play.kotlinlang.org/koans) */
/* Collections */
// Introduction
fun Shop.getSetOfCustomers(): Set<Customer> = customers.toSet()
// Filter map
// Return the set of cities the customers are from
fun Shop.getCitiesCustomersAreFrom(): Set<City> =
customers.map { it.city }.toSet()
// Return a list of the customers who live in the given city
fun Shop.getCustomersFrom(city: City): List<Customer> =
customers.filter { it.city == city }
// All Any and other predicates
fun Shop.checkAllCustomersAreFrom(city: City): Boolean =
customers
.filter { it.city != city }
.isEmpty()
fun Shop.hasCustomerFrom(city: City): Boolean =
customers
.filter { it.city == city }
.isNotEmpty()
fun Shop.countCustomersFrom(city: City): Int =
customers
.filter { it.city == city }
.size
fun Shop.findAnyCustomerFrom(city: City): Customer? =
customers
.filter { it.city == city }
.firstOrNull()
// FlatMap
val Customer.orderedProducts: Set<Product> get() =
orders
.flatMap { it.products }
.toSet()
val Shop.allOrderedProducts: Set<Product> get() =
customers
.flatMap { it.orders }
.flatMap { it.products }
.toSet()
// Max min
fun Shop.getCustomerWithMaximumNumberOfOrders(): Customer? =
customers
.sortedByDescending { it.orders.size }
.firstOrNull()
fun Customer.getMostExpensiveOrderedProduct(): Product? =
orders
.flatMap { it.products }
.toSet()
.sortedByDescending { it.price }
.firstOrNull()
// Sort
fun Shop.getCustomersSortedByNumberOfOrders() =
customers
.sortedBy { it.orders.size }
// Sum
fun Customer.getTotalOrderPrice(): Double =
orders
.flatMap { it.products }
.map { it.price }
.sum()
// Group by
fun Shop.groupCustomersByCity(): Map<City, List<Customer>> =
customers.groupBy { it.city }
// Partition
fun Shop.getCustomersWithMoreUndeliveredOrdersThanDelivered(): Set<Customer> =
customers
.partition {
it.orders.filter{ it.isDelivered == false }.size > it.orders.filter{ it.isDelivered == true}.size
}
.first
.toSet()
// Fold
fun Shop.getSetOfProductsOrderedByEveryCustomer(): Set<Product> =
customers.fold(
orderedProducts, {
orderedByAll, customer -> customer.orders
.flatMap { it.products }
.filter { it in orderedByAll }
.toSet()
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment