How to recursively implement a deep flatten on Iterable? - kotlin

Having seen flatten, I was looking for something that would be a deepFlatten, i.e., it would work with not only Iterable<Iterable<T>> (it's pretty much the same for Arrays, but let's focus on Iterable now for brevity), but also with Iterable<Iterable<Iterable<T>>>, Iterable<Iterable<Iterable<Iterable<T>>>> and so on...
Of course, the result would have to be List<T>, which the standard flatten() doesn't provide - it would return List<Iterable<T> (or a List with more nested Iterables).
I was trying to work with reified generics:
inline fun <reified E, T> Iterable<E>.deepFlatten(): List<T> = when(E::class) {
Iterable<*>::class -> (this as Iterable<Iterable<*>>).flatten().deepFlatten()
else -> flatten()
}
But this obviously is flooded with errors:
T seems pretty undeducible
You cannot have a ::class of an interface
You cannot recurse on an inline function
Are there any workarounds on the above problems? Or, even better, is there a cleaner approach to the problem?
To demonstrate an example for completeness, I'd like to be able to do:
fun main() {
val data: List<List<List<Int>>> = listOf(
listOf(listOf(1, 2, 3), listOf(5, 6), listOf(7)),
listOf(listOf(8, 9), listOf(10, 11, 12, 13))
)
print(data.deepFlatten()) // 1 2 3 4 5 6 7 8 9 10 11 12 13
}
The depth of nested Iterables (they need not be the same type - it's important that they are generically Iterable) can vary.

In Java, you might achieve the very same behavior using java-stream:
Using Collection<?>:
public static Stream<?> deepFlatMap(Object o) {
if (o instanceof Collection<?>) {
return ((Collection<?>) o).stream().flatMap(i -> deepFlatMap(i));
}
return Stream.of(o);
}
Using Iterable<?>:
public static Stream<?> deepFlatMap(Object o) {
if (o instanceof Iterable<?>) {
Spliterator<?> spliterator = ((Iterable<?>) o).spliterator();
return StreamSupport.stream(spliterator, false).flatMap(i -> deepFlatMap(i));
}
return Stream.of(o);
}
The usage is pretty straightforward: deepFlatMap(list).forEach(System.out::println);
As long as I don't know Kotlin, I hope this can at least help you with rewriting the idea.
Edit: As long as you want to specify the return target generic type, you should use another wrapper method (don't forget to change the name in the recursive method):
public static <T> Stream<T> deepFlatMap(Collection<?> collection) {
return (Stream<T>) internalDeepFlatMap(collection);
}
public static Stream<?> internalDeepFlatMap(Object o) {
if (o instanceof Collection<?>) {
return ((Collection<?>) o).stream().flatMap(i -> internalDeepFlatMap(i));
}
return Stream.of(o);
}
Usage with specifying the generic type explicitly:
MyClass.<Integer>deepFlatMap(list).map(i -> i + 1).forEach(System.out::println);

fun <T> Iterable<*>.deepFlatten(): List<T> {
val result = ArrayList<T>()
for (element in this) {
when (element) {
is Iterable<*> -> result.addAll(element.deepFlatten())
else -> result.add(element as T)
}
}
return result
}
...
println(data.deepFlatten<Int>())
You have to specify the type explicitly and you lose compile-time safety. But it can flatten lists of any nesting and with elements of different types ([1, "foo", [3, "bar"]] -> [ 1, "foo", 3, "bar"])
I would prefer a different solution. Something like this:
typealias It2<T> = Iterable<Iterable<T>>
typealias It3<T> = Iterable<It2<T>>
typealias It4<T> = Iterable<It3<T>>
typealias It5<T> = Iterable<It4<T>>
//etc...
fun <T> It3<T>.flatten2(): List<T> = flatten().flatten()
fun <T> It4<T>.flatten3(): List<T> = flatten2().flatten()
fun <T> It5<T>.flatten4(): List<T> = flatten3().flatten()
//etc...
...
println(data.flatten2())

Related

What is the type of a Kotlin 'data class'?

I have a situation where I need to create a copy of data class object. I don't know in advance which of the many data classes I have will come in into the function. I do know, however, that only data classes will be used as input to this function.
This is what didn't work:
fun doSomething(obj: Any): Any {
obj.copy(...) // <- there's no 'copy' on Any
...
}
This is what I really like to do:
fun doSomething(obj: KAnyDataClass): KAnyDataClass {
obj.copy(...) // <- works, data classes have a 'copy' method
...
}
I'm not a Kotlin developer, but it looks like the language does not support dynamic dispatch or traits. You might find success with the dynamic type, which just turns off the type-checker so it won't yell at you for using a method that it doesn't know about. However this opens up the possibility of a runtime error if you pass an argument that actually doesn't have that method.
There is no class or interface for data classes, but we know from the documentation of data classes that there are derived functions componentN and copy in each data class.
We can use that knowledge to write an abstract copy method that calls the copy method of a given arbitrary data class using reflection:
fun <T : Any> copy(data: T, vararg override: Pair<Int, Any?>): T {
val kClass = data::class
if (!kClass.isData) error("expected a data class")
val copyFun = kClass.functions.first { it.name == "copy" }
checkParameters(override, kClass)
val vals = determineComponentValues(copyFun, kClass, override, data)
#Suppress("UNCHECKED_CAST")
return copyFun.call(data, *vals) as T
}
/** check if override of parameter has the right type and nullability */
private fun <T : Any> checkParameters(
override: Array<out Pair<Int, Any?>>,
kClass: KClass<out T>
) {
override.forEach { (index, value) ->
val expectedType = kClass.functions.first { it.name == "component${index + 1}" }.returnType
if (value == null) {
if (!kClass.functions.first { it.name == "component${index + 1}" }.returnType.isMarkedNullable) {
error("value for parameter $index is null but parameter is not nullable")
}
} else {
if (!expectedType.jvmErasure.isSuperclassOf(value::class))
error("wrong type for parameter $index: expected $expectedType but was ${value::class}")
}
}
}
/** determine for each componentN the value from override or data element */
private fun <T : Any> determineComponentValues(
copyFun: KFunction<*>,
kClass: KClass<out T>,
override: Array<out Pair<Int, Any?>>,
data: T
): Array<Any?> {
val vals = (1 until copyFun.parameters.size)
.map { "component$it" }
.map { name -> kClass.functions.first { it.name == name } }
.mapIndexed { index, component ->
override.find { it.first == index }.let { if (it !== null) it.second else component.call(data) }
}
.toTypedArray()
return vals
}
Since this copy function is generic and not for a specific data class, it is not possible to specify overloads in the usual way, but I tried to support it in another way.
Let's say we have a data class and element
data class Example(
val a: Int,
val b: String,
)
val example: Any = Example(1, "x")
We can create a copy of example with copy(example) that has the same elements as the original.
If we want to override the first element, we cannot write copy(example, a = 2), but we can write copy(example, 0 to 2), saying that we want to override the first component with value 2.
Analogously we can write copy(example, 0 to 3, 1 to "y") to specify that we want to change the first and the second component.
I am not sure if this works for all cases since I just wrote it, but it should be a good start to work with.

Is there a Kotlin equivalent for Groovy's findIndexValues?

Does Kotlin have something to filter a collection and return the matching indexes?
E.g. like Groovy's findIndexValues:
http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Iterable.html#findIndexValues(groovy.lang.Closure)
Something like:
fun <T> List<T>.findIndexValues(predicate: (T) -> Boolean): List<Int> {
var indexValues = mutableListOf<Int>()
this.forEachIndexed { index, it ->
if (predicate(it)) {
indexValues.add(index)
}
}
return indexValues
}
The simplest way I can think of to do this is to use mapIndexedNotNull:
fun <T> List<T>.findIndexValues(predicate: (T) -> Boolean): List<Int> =
mapIndexedNotNull { i, t -> i.takeIf { predicate(t) } }
I don't believe there's a function for this in the standard library.
There are basically 2 simple ways according to me.
//say there is a List x of Strings
val x = listOf<String>()
//I don't believe you are looking for this.
//string is the required String of x at index.
for ((index, string) in x.withIndex()) {
TODO()
}
//2nd method is using filterIndexed
/**
* Returns a list containing only elements matching the given predicate.
* #Params: predicate - function that takes the index of an element and the element itself and returns the result of predicate evaluation on the element.
*/
x.filterIndexed { index, string ->
TODO()
}
I like #Sam's answer, but I find this implementation to be slightly more readable as it filters explicitly on predicate as opposed to implicitly via null:
fun <T> List<T>.findIndexValues(predicate: (T) -> Boolean): List<Int> =
withIndex().filter { (_, t) -> predicate(t) }.map { it.index }

Proper use of Number class in Kotlin

Can anyone help me implement these methods in Kotlin?
I want to find min, max elements of array of numbers and also sort array in ascending order. Here is a code
class DataArray<Number>(vararg numbers: Number) {
private val array = mutableListOf<Number>(*numbers)
fun getMin() {
return array.minByOrNull { it! } //doesn't work
}
fun getMax() = array.max() //doesn't work
fun sort() = array.sort() //doesn't work
private fun <E> MutableList<E>.max(): Any { //was created to use in function above, but resulted in stack overflow
return this.max()
}
private fun <E> MutableList<E>.sort(): Any { //was created to use in function above, but resulted in stack overflow
return this.sort()
}
override fun toString(): String {
var str = ""
for(i in array)
str += "$i "
return str
}
}
fun main() {
val arr = DataArray(2, 5, 2, 6, 9, -3, 56, 16, 72, 8)
println(arr.getMax())
println(arr.getMin())
println(arr.sort())
print(arr)
}
Note that the word Number here declares a generic parameter called Number. It does not refer to kotlin.Number. You might have intended it to declare a generic parameter with a bound of Number instead, in which case you should have written:
class DataArray<T: Number>(vararg numbers: T) {
...
}
But even if you did, it still wouldn't work as Numbers are not comparable.
You would have to further constrain T to Comparable<T>:
class DataArray<T: Number>(vararg numbers: T) where T: Comparable<T> {
Then you can do:
fun getMin() = array.minOrNull()
fun getMax() = array.maxOrNull()
fun sort() = array.sort()
Extension functions on MutableList are unnecessary.
(Note that technically, the T: Number constraint is also unnecessary if you just want to use minOrNull, maxOrNull, and sort. I'm assuming you are planning on using one of the methods in kotlin.Number. Otherwise you can delete that constraint.)
You seem to be trying to implement your own MutableList by delegation. Keep in mind that you can easily do this using by:
class DataArray<T: Number>(
vararg numbers: T
) : MutableList<T> by mutableListOf(*numbers) {
override fun toString(): String {
var str = ""
for(i in this) // rather than "array", use "this"
str += "$i "
return str
}
}

How does Kotlin choose the generic overloaded function to call?

I'm trying to write serialization functions to be able to serialize any vector (=ArrayList) in Kotlin, as well as primitive types and classes extending a Serialize class having a toBinary() function.
I also have a custom WriteDataStream class (code below) to serialize fields with the right format, endianness, etc.
I'm new to Kotlin but have experience in C++. In C++, I used templates and template specialization to solve that problem easily, but with Kotlin I've been struggling for a few days, without success.
I have a custom vector class MyVector which extends ArrayList and adds a maximum size. I want to serialize it with any generic type T, including inner vectors like a MyVector<MyVector<MyClass>>.
My WriteDataStream contains the following:
inline fun <reified T> write(vector: MyVector<T>) {
this.writeSize(vector.size.toULong(), vector.MAX_SIZE)
for (element in vector) {
write<T>(element)
}
}
inline fun <reified T: Serialize> write(value: T) {
writeSerialize(value as Serialize)
}
inline fun <reified T> write(value: T) {
when (T::class) {
UByte::class -> {
writeUInt8(value as UByte)
}
UShort::class -> {
writeUInt16(value as UShort)
}
UInt::class -> {
writeUInt32(value as UInt)
}
ULong::class -> {
writeUInt64(value as ULong)
}
Byte::class -> {
writeInt8(value as Byte)
}
Short::class -> {
writeInt16(value as Short)
}
Int::class -> {
writeInt32(value as Int)
}
Long::class -> {
writeInt64(value as Long)
}
Boolean::class -> {
writeBoolean(value as Boolean)
}
Float::class -> {
writeFloat(value as Float)
}
Double::class -> {
writeDouble(value as Double)
}
else -> {
error("Default serialization:" + T::class.qualifiedName)
}
}
}
All the underlying functions writeXXX() are tested and work fine. However, when tying to serialize a MyVector with a class extending Serialize, I fall in the "Default serialization" case:
#Test
fun writeVectorOfStructure() {
class TestStructure: Serialize() {
override fun toBinary(stream: WriteDataStream) {
stream.writeUInt32(17U)
stream.writeUInt8(3U)
stream.writeDouble(555.555)
}
}
val value = MyVector<TestStructure>(MAX_SIZE, arrayListOf(TestStructure(), TestStructure()))
writeStream.write(value)
val bytes: UByteArray = writeStream.byteArray()
Assert.assertEquals(bytes.size, 28) // = 2 (for size) + 2*(4+1+8) = 28 bytes
}
So my question is: Why does Kotlin not use the function
inline fun <reified T: Serialize> write(value: T)
when it serializes an element of the vector (write<T>(element)) with generic T = Serialize, but instead uses the more generic one?
inline fun <reified T> write(value: T)
In C++, the compiler always uses the most fitted function.
Is there a way to overcome this limitation in Kotlin?
I have tried with and without reified types, I have tried a non-generic function as well: inline fun write(value: Serialize), but without success. The only thing that seems to work was to add a case for classes "instance of" Serialize in the fully-generic inline fun <reified T> write(value: T), but this is not really a nice solution.
Thanks you !
JVM and its bad implementation of generics
You are a victim of Java's implementation of generics, more specifically the erasure. C++ uses what is called type expansion to implement generics, meaning if you declare MyType<A> and MyType<B>, at runtime you will have two different types, language runtime will create them for you.
On the other hand what Java does is called the erasure implementation. so in java world when you say List<String> and List<Integer>, at runtime they are both identical types, that is system doesn't have any information to make a distinction between both of these, they are List type (Note that there is no type parameter, it got removed during the compilation).
Lets decompile your code and see for yourself
I wrote following code in kotlin, it matches yours
class SomeType {
inline fun <reified T: String> write(value: T) {}
inline fun <reified T> write(value: T) {}
inline fun <reified T: Any> write(vector: List<T>) {
for (element in vector) {
write(element)
}
}
}
And when I decompile the code it gives me following. (Only relevant code included)
public final class SomeType {
public final void write(#NotNull String value) {}
public final void write(Object value) {}
public final void write(#NotNull List vector) {
boolean var6;
for(Iterator var4 = vector.iterator(); var4.hasNext(); var6 = false) {
Object element = var4.next();
}
}
}
Look at the write(vector: List<T>) method's decompilation. parameter type got changed to List which is a Raw Type and its components are objects.
And for an Object best method match is public final void write(Object value) and not the one with String or in your case Serialize.

Is there a way to construct a HashSet with initializator function in Kotlin?

To read Stars from a file in the Facebook Hacker Cup's 2016 Boomerang Constelations problem, following extension function can be defined:
fun BufferedReader.readStars(n: Int): Set<Star> {
return Array(n) {
val (l1, l2) = readLine().split(" ").map { it.toInt() }
Star(l1, l2)
}.toHashSet()
}
Code is compact but the values are first read into an array and then converted to a HashSet. Is there a way to directly initialize a HashSet with the size of n and initializator function in Kotlin?
UPDATE: Is there an existing way in standard Kotlin libs?
You can always use apply to initialize objects in-place:
HashSet<Star>(n).apply {
repeat(n) {
val (l1, l2) = readLine()!!.split(' ').map { it.toInt() }
put(Star(l1, l2))
}
}
If that's too inconvenient too type every time, write an extension function:
inline fun <T> createHashSet(n : Int, crossinline fn: (Int) -> T) = HashSet<T>(n).apply {
repeat(n) { add(fn(it)) }
}
Usage:
createHashSet<Star>(n) {
val (l1, l2) = readLine()!!.split(' ').map { it.toInt() }
Star(l1, l2)
}
Since HashSet is a java class so you can only initialize it in a way provided by JDK.
While there's no helper method in Kotlin runtime it's easy to write it yourself like so:
public fun <T> hashSetOf(size: Int, initializer: (Int) -> T): HashSet<T> {
val result = HashSet<T>(size)
0.rangeTo(size - 1).forEach {
result.add(initializer(it))
}
return result
}
As #miensol has pointed out HashSet initialization is limited to the constructors made available by the JDK. Kotlin has added a hashSetOf function which initializes an empty HashSet and then adds the specified elements to it.
To avoid first reading the values into an array you can use a kotlin.Sequence who's "values are evaluated lazily":
fun BufferedReader.readStars(n: Int): Set<Star> {
return lineSequence().take(n).map {
val (l1, l2) = it.split(" ").map { it.toInt() }
Star(l1, l2)
}.toHashSet()
}
It seems like you are asking an XY question (http://xyproblem.info/). You really want to know how to write readStars in the most efficient way, but instead you ask about HashSet. I think #mfulton26 answers your question as well depending on what is being asked.
Here is the answer for "how do I write this in the most efficient way:"
You have two options. First, a version that auto-closes the stream at the end:
fun BufferedReader.readStars(n: Int): Set<Star> {
return use {
lineSequence().map { line ->
val idx = line.indexOf(' ')
Star(line.substring(0, idx).toInt(), line.substring(idx + 1).toInt())
}.toSet()
}
}
And second, a version that does not:
fun BufferedReader.readStars(n: Int): Set<Star> {
return lineSequence().map { line ->
val idx = line.indexOf(' ')
Star(line.substring(0, idx).toInt(), line.substring(idx+1).toInt())
}.toSet()
}
Neither version creates an array, neither do they make copies of data. They stream the data through a sequence which creates the Set and fills it directly.
Other notes
No need to use split if you are really concerned about allocations and performance. Just use indexOf(char) and split the string yourself using substring.
If you do a split, then please use split(char) not split(String) when you are looking to split on a char