Skip to content

Instantly share code, notes, and snippets.

@asad-awadia
Forked from bastman/cartesianProduct.kt
Created March 31, 2022 23:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asad-awadia/29a5aae6e03496b84cd8376896e8f547 to your computer and use it in GitHub Desktop.
Save asad-awadia/29a5aae6e03496b84cd8376896e8f547 to your computer and use it in GitHub Desktop.
Kotlin collections - leftJoin,innerJoin, ...
infix fun <T,O>List<T>.cartesianProduct(others:List<O>):List<Pair<T,O>> =
flatMap{ t:T->
others.map { o-> Pair(t,o) }
}
inline fun <T, O, R> List<T>.mapCartesianProduct(others: List<O>, transform: (Pair<T, O>) -> R): List<R> =
flatMap { t: T ->
others.map { o -> transform(Pair(t, o)) }
}
Example:
val r:List<Pair<String,Int>> = (listOf("A","B") cartesianProduct listOf(100,200,300))
// Pair("A",100), Pair("A",200), Pair("A",300), Pair("B",100), ...
package com.example.demo
data class User(val id: String)
data class Book(val id: String, val userId: String)
fun main(args: Array<String>) = App().run()
class App {
fun run() {
val users: List<User> = listOf(
User(id = "u1"),
User(id = "u2"),
User(id = "u3")
)
val books: List<Book> = listOf(
Book(id = "b1.u1", userId = "u1"),
Book(id = "b2.u1", userId = "u1"),
Book(id = "b3.u2", userId = "u2"),
Book(id = "b4.ux", userId = "ux")
)
println("==== given: users .... =====")
println(users)
println("==== given: books .... =====")
println(books)
println("=== JOIN users to books ....")
println("=> innerJoinFirst (A) book, user... ====")
books
.innerJoinFirst(users) { book: Book, user: User -> book.userId == user.id }
.forEach(::println)
println("=> innerJoinFirst (B) book, user ... ====")
books
.innerJoinFirst(users.associateBy { it.id }) { book: Book, usersById: Map<String, User> ->
usersById[book.userId]
}
.forEach(::println)
println("=> joinNotNull (A) ... ====")
books
.joinNotNull(users) { book: Book, user: User -> book.userId == user.id }
.forEach(::println)
println("=> joinNotNull (B) ... ====")
books
.joinNotNull(users.associateBy { it.id }) { book: Book, usersById: Map<String, User> ->
usersById.values.filter { book.userId == it.id }
}
.forEach(::println)
println("==== JOIN NOT NULL (A) user, books ===")
users.joinNotNull(books) { user: User, book: Book ->
book.userId == user.id
}.forEach(::println)
println("====INNER JOIN (A) user, books ===")
users.innerJoinFirst(books) { user: User, book: Book ->
book.userId == user.id
}.forEach(::println)
println("=> leftJoinFirst user,book ... ====")
users
.leftJoinFirst(books) { user: User, book: Book -> book.userId == user.id }
.forEach(::println)
println("=> leftJoinFirst book,user ... ====")
books
.leftJoinFirst(users) { book: Book, user: User -> book.userId == user.id }
.forEach(::println)
println(
""" |
| INNER (book, user)
| ==================
| """.trimMargin()
)
println("=> flatMapInnerJoin book,user ... ====")
books
.flatMapInnerJoin(users) { book: Book, user: User -> book.userId == user.id }
.onEach(::println)
println("=> mapInnerJoin book,user ... ====")
books
.mapInnerJoin(users) { book: Book, user: User -> book.userId == user.id }
.onEach(::println)
println("=> innerJoinFirst book,user ... ====")
books
.innerJoinFirst(users) { book: Book, user: User -> book.userId == user.id }
.onEach(::println)
println(
""" |
| INNER (user, book)
| ==================
| """.trimMargin()
)
println("=> flatMapInnerJoin user,book ... ====")
users
.flatMapInnerJoin(books) { user: User, book: Book -> book.userId == user.id }
.onEach(::println)
println("=> mapInnerJoin user,book ... ====")
users
.mapInnerJoin(books) { user: User, book: Book -> book.userId == user.id }
.onEach(::println)
println("=> innerJoinFirst user,book ... ====")
users
.innerJoinFirst(books) { user: User, book: Book -> book.userId == user.id }
.onEach(::println)
println(
""" |
| LEFT (book, user)
| ==================
| """.trimMargin()
)
println("=> flatMapLeftJoin book,user ... ====")
books
.flatMapLeftJoin(users) { book: Book, user: User -> book.userId == user.id }
.onEach(::println)
println("=> mapLeftJoin book,user ... ====")
books
.mapLeftJoin(users) { book: Book, user: User -> book.userId == user.id }
.onEach(::println)
println("=> leftJoinFirst book,user ... ====")
books
.leftJoinFirst(users) { book: Book, user: User -> book.userId == user.id }
.onEach(::println)
}
}
private fun <A:Any,B:Any> List<Pair<A?,B>>.filterFirstNotNull():List<Pair<A,B>> {
return this.mapNotNull {
val fst:A? = it.first
when (fst) {
null -> null
else -> fst to it.second
}
}
}
private fun <A:Any,B:Any> List<Pair<A,B?>>.filterSecondNotNull():List<Pair<A,B>> {
return this.mapNotNull {
val s:B? = it.second
when (s) {
null -> null
else -> it.first to s
}
}
}
inline fun <T : Any, O : Any> List<T>.joinNotNull(others: List<O>, on: (a: T, b: O) -> Boolean): List<Pair<T, List<O>>> =
map { it: T -> it to others.filter { o: O -> on(it, o) } }
inline fun <T : Any, O : Any, K : Any> List<T>.joinNotNull(
others: Map<K, O>, on: (a: T, b: Map<K, O>) -> List<O?>
): List<Pair<T, List<O>>> =
map { it to on(it, others).filterNotNull() }
inline fun <T : Any, O : Any> List<T>.leftJoinFirst(others: List<O>, on: (a: T, b: O) -> Boolean): List<Pair<T, O?>> =
map { it to others.firstOrNull { o: O -> on(it, o) } }
inline fun <T : Any, O : Any, K : Any> List<T>.leftJoinFirst(
others: Map<K, O>, on: (a: T, b: Map<K, O>) -> O?
): List<Pair<T, O?>> =
map { it to on(it, others) }
inline fun <T : Any, O : Any, K : Any> List<T>.innerJoinFirst(
others: Map<K, O>, on: (a: T, b: Map<K, O>) -> O?
): List<Pair<T, O>> =
mapNotNull {
val theOther: O? = on(it, others)
when (theOther) {
null -> null
else -> it to theOther
}
}
inline fun <T : Any, O : Any> List<T>.flatMapInnerJoin(
others: List<O>, on: (a: T, b: O) -> Boolean
): List<Pair<T, O>> =
flatMap {
others
.filter { o: O -> on(it, o) }
.map { o: O -> it to o }
}
inline fun <T : Any, O : Any> List<T>.mapInnerJoin(
others: List<O>, on: (a: T, b: O) -> Boolean
): List<Pair<T, List<O>>> =
mapNotNull {
val theOthers: List<O> = others.filter { o: O -> on(it, o) }
when (theOthers.isEmpty()) {
true -> null
false -> it to theOthers
}
}
inline fun <T : Any, O : Any> List<T>.innerJoinFirst(
others: List<O>, on: (a: T, b: O) -> Boolean
): List<Pair<T, O>> =
mapNotNull {
val theOther: O? = others.firstOrNull { o: O -> on(it, o) }
when (theOther) {
null -> null
else -> it to theOther
}
}
inline fun <T : Any, O : Any> List<T>.flatMapLeftJoin(others: List<O>, on: (a: T, b: O) -> Boolean): List<Pair<T, O?>> =
flatMap { me ->
val theOthers: List<O> = others.filter { o: O -> on(me, o) }
if (theOthers.isEmpty()) {
listOf(me to null)
} else {
theOthers.map { o -> me to o }
}
}
inline fun <T : Any, O : Any> List<T>.mapLeftJoin(others: List<O>, on: (a: T, b: O) -> Boolean): List<Pair<T, List<O>>> =
map { me ->
val theOthers: List<O> = others.filter { o: O -> on(me, o) }
me to theOthers
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment