Initialize Array of non-optionals without using constructor - arrays

I am using an Array of non-optional values, and I want them to stay non-optional, but I can't use Array's default constructor because of problems described here.
Furthermore, the .also{} trick described in the linked won't work for me, because mine is not an array of some primitive type with its own special WhateverArray class.
Is there some Kotlin trick by which I can initialize my a below? Or must I resort to building some list and then converting it?
// please assume Stream<MyNonprimitiveType> magically gives me
// size() -> Int and
// next() -> MyNonprimitiveType
val stream : Stream<MyNonprimitiveType> = Stream<MyNonprimitiveType>()
val size : Int = stream.size()
val a : Array<MyNonprimitiveType> = ??? // use stream.next()

Here's a complete example doing what you want, without using a temporary list:
class Stream<T>(private val list: List<T>) {
val size = list.size;
private val it = list.iterator()
fun next(): T {
return it.next()
}
}
inline fun <reified T: Any> Stream<T>.toArray(): Array<T> {
val tmp: Array<T?> = arrayOfNulls(size)
for (i in 0 until size) {
tmp[i] = next()
}
return tmp as Array<T>
}
fun main() {
val stream : Stream<String> = Stream(listOf("a", "b"))
val a: Array<String> = stream.toArray()
println(Arrays.toString(a))
}

Related

Kotlin foreach object

I have a object class,
object Examples {
const val E = 1
const val X = 2
const val A = 3
const val M = 4
const val P = 5
const val L = 6
}
if I use
Examples.E
it will reference the relevant const val, but how can I iterate over each val without calling them individually?
It looks like you want an enum:
enum class Example(val intVal: Int) {
E(1), X(2), A(3), M(4), P(5), L(6);
}
You can access specific values like Example.E.intVal. To get a collection of all the values, you can do Example.values() or enumValues<Example>()
Well, best way to do this is use Enum class.
But you also could implement Iterable interface on yours object. And after this you will be able to use forEach/map/fold/filter and other useful Iterable extension functions
object Examples : Iterable<Int> {
const val E = 1
const val X = 2
const val A = 3
const val M = 4
const val P = 5
const val L = 6
override fun iterator(): Iterator<Int> {
return object : Iterator<Int> {
private var i = 1
override fun hasNext(): Boolean = i <= 6
override fun next(): Int {
return when (i++) {
1 -> E
2 -> X
3 -> A
4 -> M
5 -> P
6 -> L
else -> error("No such element exeption")
}
}
}
}
}
Examples.forEach {
println(it)
}
With Kotlin, you could use reflection to get all values inside an object.
However, did you consider using an Enum class? This seems like it would fit your use case better:
enum class Letter {
A,
B,
C
}
You can get all possible values for Letter using
Letter.values()
Or if what you want is to be able to reference repeated elements in order, you could use an array, or just a string, if the elements are always letters.
Also keep in mind you have two values called "E" defined, which wouldn't work.

Initialize array with generic type in kotlin

I want to implement stack data structure using kotlin. I want to use generic array so as to create stack of any datatype. I am not sure how to initialize the array properly. It shows different kind of errors everytime. Also cannot figure out how to use List<T>. Any kind of help will be appreciated.
class StackADT<ANY>(var capacity: Int) {
private var top = -1
private val stack: (generic type array)//NEED TO INITIALIZE PROPERLY HERE
fun push(element: ANY) {
if (top == capacity)
throw Exception("Overflow occurred in stack!!")
stack[++top] = element
}
....
class StackADT<T>(var capacity: Int) {
private var top = -1
private val stack: ArrayList<T> = ArrayList(capacity)
fun push(element: T) {
if (top == capacity)
throw Exception("Overflow occurred in stack!!")
top++
stack.add(element)
}
...
You can test here: Kotlin Playground
Another way:
var stack = arrayOfNulls<Any?>(capacity) as Array<T>

Mapping arrays to list of objects kotlin

I'm wondering about methods of mapping multiple arrays into one list of object.
I mean e.g. I have
val a = arrayOf("A1","A2","A3")
val b = arrayOf("B1","B2","B3")
and
data class SomeClass(val v1:String, val v2:String)
I want to parse it in elegant way to have list like that:
val list = listOf(SomeClass("A1","B1"),SomeClass("A2","B2"),SomeClass("A3","B3"))
I assume they are of the same length. The only way I thought of is:
val list = mutableListOf<SomeClass>()
for (i in a.indices)
array.add(SomeClass(a[i],b[i])
Is there a better, more elegant solution (maybe using Collecions.zip or Array.map)?
Try Array.zip and then map:
val list = a.zip(b)
.map { SomeClass(it.first, it.second) }
or if you like it more:
val list = a.zip(b)
.map { (a, b) -> SomeClass(a, b) }
Note that if both arrays differ in size, the additional values are ignored. Note also that this will create intermediate Pairs (which is the default transformation function of zip). Even though I like the explicit map more, #hotkeys solution regarding the overloaded method is more appropriate (you spare that hidden Pair-transformation):
val list = a.zip(b) { a, b -> SomeClass(a, b) }
And where the overloaded method probably shines, is when using references instead:
a.zip(b, ::SomeClass)
Which will work as long as you have a constructor matching the zipped arguments and doesn't work out of the box for the Pair (yet?).
Improving on #Roland's answer, you can use the zip overload that accepts a two-argument function for mapping the pairs immediately:
val result = a.zip(b) { x, y -> SomeClass(x, y) }
You can write some custom fun like this:
inline fun <T, R, E, V> Iterable<T>.zipThree(other1: Iterable<R>, other2: Iterable<E>, transform: (T, R, E) -> V): List<V> {
val first = iterator()
val second = other1.iterator()
val third = other2.iterator()
val list = ArrayList<V>()
while (first.hasNext() && second.hasNext()) {
list.add(transform(first.next(), second.next(), third.next()))
}
return list
}
And use this transform for getting List
val strings = listOf("1", "2")
val ints = listOf(1, 2)
val boolean = listOf(true, false)
val listYoutObjects = strings.zipThree(ints, boolean) { one, two, three -> YouObject(one, two, three) }

How to check a generic type inside a Kotlin function?

I am using Kotlin to parse JSON. For example, I have this representation of a country: {"code":"US", "name":"United States of America"}. To produce a Country object from such a JSONObject, I have this function:
val produceCountry = fun (js: JSONObject) =
Country(js.getString("code"), js.getString("name"))
I can easily parse an array of Country with this function. Besides arrays of Country, however, I also have arrays of Cat, Car, Cart, CordlessPhone, etc. Each has their own produce* function transforming a JSONObject to a Kotlin object of that type. To generalize array parsing, I have this function:
fun <T> produceSetOf(array: JSONArray, element: (JSONObject) -> T): Set<T> {
val set = mutableSetOf<T>()
for (i in 0 until array.length())
set.add(element(array.getJSONObject(i)))
return set
}
So I can call produceSetOf(jsonArray, produceCountry) on encountering an array whose elements are of type Country. This works well on arrays of Cat, Car, Cart, CordlessPhone too.
Problem arises when I see an array of strings. Instead of array.getJSONObject(i), I have to use array.getString(i). In effect, I am thinking of introducing another parameterized type to the function above and have it make the call differently:
fun <S,T> produceSetOf(array: JSONArray, element: (S) -> T): Set<T> {
val set = mutableSetOf<T>()
for (i in 0 until array.length()) {
when (S) {
is String ->
set.add(element(array.getString(i)))
is JSONObject ->
set.add(element(array.getJSONObject(i)))
}
}
return set
}
Of course, Kotlin does not allow me to do that. Any suggestion how I could do that while maintaining the generality of produceSetOf() and without introducing another layer of abstraction (e.g. an element iterator, or a function transforming an index into String/JSONObject)?
Thank you.
Here is one possible solution using reified type parameters.
inline fun <reified S, T> produceSetOf(array: JsonArray, element: (S) -> T): Set<T> {
val set = mutableSetOf<T>()
for (i in 0 until array.size()) {
when (S::class) {
String::class -> set.add(element(array[i].string as S))
JsonObject::class -> set.add(element(array[i].obj as S))
}
}
return set
}
val stringArray = listOf("1", "2").toJsonArray()
val stringSet = produceSetOf<String, Int>(stringArray) { it.toInt() }
println(stringSet) // prints [1, 2]
val objArray = listOf(jsonObject("key" to "value"), jsonObject("key" to "other")).toJsonArray()
val objSet = produceSetOf<JsonObject, String>(objArray) { it["key"].string }
println(objSet) // print [value, other]
I used gson for the Json objects, since I didn't know where yours were from.
A possible shorter solution:
inline fun <reified S, T> produceSetOf(array: JsonArray, element: (S) -> T): Set<T> = array.map {
when (S::class) {
String::class -> element(it.string as S)
JsonObject::class -> element(it.obj as S)
else -> throw UnsupportedOperationException("${S::class.simpleName} is not supported")
}
}.toSet()

Swift Cast as Generic crashing with UInt

Why does the following Array extension crash if the array used with it is of type UInt, but works if the array is of type Int or String?
extension Array
{
func indexOf<T:Equatable>(value:T) -> Int?
{
for (i, val) in enumerate(self)
{
if (val as T == value)
{
return i;
}
}
return nil;
}
}
var a:[UInt] = [243, 234, 1, 212, 3, 56, 88, 11, 77];
var i = a.indexOf(234);
Error produced:
Playground execution failed: error: Execution was interrupted, reason: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
* thread #1: tid = 0x27a3c, 0x00000001079d3f27 libswift_stdlib_core.dylibswift_dynamicCast + 1063, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
* frame #0: 0x00000001079d3f27 libswift_stdlib_core.dylibswift_dynamicCast + 1063
frame #1: 0x00000001137bbbc8
The problem is that the T: Equatable that you define is unrelated to the T that is stored in the array. When you do val as T, you are converting from the array value type to your new local T that is required to be equatable.
When you call indexOf with a literal, it is not being forced into the same type as is stored in a because the type is not enforced to match by your extension.
You are better off with a function to get the index of an object in an array:
func indexOfObject<T : Equatable>(object: T, inArray collection: [T]) -> Int? {
var index : Int = 0
for testObject in collection {
if testObject == object {
return index
}
index++
}
return nil
}
That strictly enforces that the T type is equatable and matches the type of the object passed in.
Better yet, you might want to use an extension like this:
extension Array {
func indexOfObjectPassingTest(test: (object: T) -> Bool) -> Int? {
var index : Int = 0
for object in self {
if test(object: object) {
return index
}
index++
}
return nil
}
}
That is more flexible and allows you to do:
var i = a.indexOfObjectPassingTest({$0 == 234})
Notice also that I do not define T for my method because it is already defined in the Array itself.

Resources