Get value from Dictionary<String, Any> - ios7

I declared a Dictionary<String, Any> which has some Strings, Arrays and ints as values.
When I try to get back a value based on String key, I'm not able to cast it to Array,
even if that value identified by key is a real Array.
let lColorValues = lTabBarDictionary[TabBarKey.tabBarColor] as Array;
p.s. TabBarKey.tabBarColor is a string
Apple's Swift Programming Book offers an example with an Array which store different kinds of objects, and they use as to downcast objects, which seems to work fine for Array but not for Dictionary.
Did I missed something ? How to get values for such Dictionary ?

You have to specify the type the Array holds, for example:
class TabBarKey {
class var tabBarColor : String {
return "key"
}
}
let arr = ["1", "2", "3"]
var lTabBarDictionary = Dictionary<String, Any>()
lTabBarDictionary[TabBarKey.tabBarColor] = arr
let val = lTabBarDictionary[TabBarKey.tabBarColor] as Array<String>
in the last line, I am using Array<String> instead of Array. You should do the same thing, using of course the proper generic type that the array holds.
Tested that code in playground and it prints the expected array.

Related

How to initialize List< List<Int> > in Kotlin?

As per leetcode question here I am required to return List<List<Int>> type for Kotlin submission.
I tried using listOf() but unable to create.
My another guess was to use LinkedList of type List:
var result: List<List<Int>> = LinkedList<List<Int>>()
The intelliJ idea gives no warnings for the above declaration but add() is not available on result variable. Please let me know what I am doing wrong.
How should I initialize empty List<List<Int>> type in kotlin?
add is not available for List. It's available for MutableList. LinkedList is a MutableList, but you are upcasting it to a plain List by assigning it to a variable of type List.
If you need to work with a MutableList or LinkedList inside this function, you can do so by not declaring the type of the result variable so it will implicitly be a MutableList or LinkedList. When you return it from the function, it will be implicitly upcast at that time, when you no longer need the mutable features.
fun threeSum(nums: IntArray): List<List<Int>> {
val output = mutableListOf<MutableList<Int>>()
// logic
return output
}
or
fun threeSum(nums: IntArray): List<List<Int>> {
val output = LinkedList<LinkedList<Int>>()
// logic
return output
}
LinkedList is a specific type of MutableList that compared to the default MutableList (ArrayList) is heavier and slower at accessing specific elements in the middle, but faster at accessing elements at the start/end and faster at inserting or removing elements. You will most commonly just want to use mutableListOf to instantiate mutable lists.
you can use
var result: List<List<Int>> = listOf(listOf())
or
var result = listOf(listOf<Int>())

sortedBy() selector not sorting List

I have a sortedBy{} statement which intends to sort a List by the length of the String elements:
var animals: List<String> = listOf("tiger", "cat", "dragon", "elephant")
fun strLength(it: String) = it.length
animals.sortedBy { strLength(it) }
animals.forEach {println(it)}
However it only prints the initial order. Any idea why?
You have to assign the output of sortedBy.
animals = animals.sortedBy { strLength(it) }
Because, like many other functions in Kotlin, sortedBy doesn’t mutate the input & honour immutability. So it returns a new collection. So it mitigates side-effects. Kotlin encourages this immutable approach. However, there are mutable counterparts of these collections if required.
sortedBy does not sort the list, instead it returns a new list which has the elements sorted. If you don't want a new list, simply use sortBy.

How to change pair value in arguments in Kotlin

I know Pair is immutable in Kotlin. The question is that arguments is also immutable in Kotlin. So when I got a code like this.
fun bind(pair: Pair<String, Boolean>) {
// Change pair value here
}
pair = pair.copy() is not working here. I don't know how to do.
As Pair is immutable, you can't just replace the pair value except you are using reflection. Either change Pair to something mutable or stick with it and return a new Pair instead either with copy (setting only some of the values) or with the following:
fun bind(pair: Pair<String, Boolean>) = pair.let { (left, right) -> // destructuring
// exchange pair values here... just showing a sample:
left.toInt() to right.toString() // this is basically the same as Pair(left.toInt(), right.toString())
} // in this example it returns a Pair<Int, String>
While you could probably introduce your own MutablePair-class I would rather stick to the immutability and adapt your code to handle it appropriately. Mutability can be a problem; even more so if someone else does not expect that your pair is mutable.
You can not write to the pair value itself since it's immutable, instead create a copy of the value like so:
val pair2 = pair.copy()
And use pair2 value instead of pair itself.
Also see this helpful answer.
You can use copy() to create a changed copy. (Works for every data-class.)
fun bind(pair: Pair<String, Boolean>) {
val pairCopy = pair.copy(first = "something else")
}
Then use pairCopy in the following code.

Observable array in Kotlin to know when an array elt value is changed

My goal: I have a simple class with a public
val reds = IntArray(10)
val greens = IntArray(10)
val blues = IntArray(10)
val lums = IntArray(10)
If someone modifies any red value, I'd like to update the lum value.
myObj.reds[5] = 100 // Should update myObj.lums[5] = reds[5]+greens[5]+blues[5]
The problems is that the by Delegates.observable seem to only be used for var objects - nothing mentions "and if you modify an element of an array, here is what gets triggered"
Maybe this isn't possible and I have to do all modifications through getters and setters - but I'd much rather have something trigger like an observable!
You will have to use a custom class instead, IntArray is mapped to primitive int[] array so it doesn't provide any place to inject callback - changing value like your example (myObj.reds[5] = 100) you only know when array is returned, but have no control over changes after that.
For example you can create class like this:
class IntArrayWrapper(size: Int,
val setterObs : ((index: Int, value: Int) -> Unit)? = null){
val field = IntArray(size)
val size
get() = field.size
operator fun iterator() = field.iterator()
operator fun get(i: Int) : Int {
return field[i]
}
operator fun set(i: Int, value: Int){
field[i] = value
setterObs?.invoke(i, value)
}
}
Operator functions will let you get values from underlying array with same syntax as if you were accessing it directly. setterObs argument in constructor lets you pass the "observer" for setter method:
val reds = IntArrayWrapper(10){index, value ->
println("$index changed to $value")
invalidateLums(index) // method that modifies lums or whatever you need
}
val a = reds[2] // getter usage
reds[3] = 5 // setter usage that triggers the setter observer callback
reds.field[4] = 3 // set value in backing array directly, allows modification without setter callback
Note that this imposes limitations, as you won't be able to freely use IntArray extension methods without referencing backing field nor will you be able to pass this class as an Array argument.
I do not know if it is the cleanest way of solving your problem but, you could use the ObservableList (FX observable collections):
var numbers: ObservableList<Int> = FXCollections.observableArrayList()
numbers.addListener(ListChangeListener<Int> {
//Do things on change
})
But as I mentioned, by adding these collections you are mixing FX components into your application, which I do not know if it is wanted or even if it works on various platforms like android!

How to create list in Kotlin?

I tried these in Kotlin REPL
var listA = listOf(null ,null)
var listB = [null, null]
The first line works fine as expected. On displaying listA I get:
[null, null]
The second line throws the following error:
error: cannot use 'Nothing?' as reified type parameter
var listB = [null,null]
^
error: unsupported [Collection literals outside of annotations]
var listB = [null,null]
^
error: unsupported [Array<Nothing> in return type is illegal]
var listB = [null,null]
^
When I try the same with non null types,
i.e.
var listC = [1,2]
I get this error:
error: unsupported [Collection literals outside of annotations]
var listC = [1,2]
^
I'm new to Kotlin. Can someone please explain what is going on here?
From the Kotlin documentation on Collections:
Kotlin does not have dedicated syntax constructs for creating lists or sets. Use methods from the standard library, such as listOf(), mutableListOf(), setOf(), mutableSetOf().
There are no list literals currently for code outside of annotations.
As #Carcigenicate pointed out, there is not syntax for [null, null].
However, Kotlin does have some handy methods for handling lists and arrays.
Lists
listOf()
Creates a new read-only List.
listOfNotNull()
Basically the same as listOf(), but without null values. Even empty strings
are skipped.
arrayListOf()
Creates an ArrayList. This time you can modify (add/remove) elements.
mutableListOf()
Behaves like arrayListOf(). Actually, mutableListOf() internally uses ArrayLists. Read more
Arrays
arrayOf()
This creates an array, which is very different to most languages you know.
Instead of syntax structures like {1, 2, 3} or [1, 2, 3] you have functions
in Kotlin. You also get functions for typed array:
booleanArrayOf()
doubleArrayOf()
charArrayOf()
...
One exception are annotations, which explains your compiler error [Collection literals outside of annotations]:
#MyAnnotation(arguments = [1, 2, 3])
However, this could change in the future as discussed here.
While working with arrays, it is important to know the return types those functions are creating.
As an example:
Array<Int> is an Integer[] under the hood, while IntArray is a primitive int[] when targeting the JVM.
So for the case of mutable lists, you can declare an empty String one with: val list: MutableList<String> = mutableListOf(). If you wanted an immutable list then you could use val like so: val list: List<String> = listOf("x", "y", "z").
Also note, that you should consider your use case for using val or var. Mutability of a list pertains to values within the list itself, where as val and var are for the variable. You can reassign the list if you use var but not val (similar to final of Java)
For the sake of clarity, as an example, mutable lists can have elements added an removed after their initialisation, while immutable cannot.
Immutable Lists Docs
Mutable List Docs
You get [null, null] because that's how toString() happens to be defined in java.util.AbstractCollection and listOf creates a java.util.ArrayList which inherits this implementation.
The errors you get are because there is a place in Kotlin where this syntax happens to work: annotation parameters. So the parser understands it. But it creates arrays, not lists, and so your code wouldn't compile even if the syntax wasn't limited to annotations.
Yes this is not the correct syntax for creating List with Kotlin.
Here is an example of List and MutableList(with write operations) and some of the operations you can do on them:
List
val numbers = listOf("one", "two", "three", "four")
println("Number of elements: ${numbers.size}")
println("Third element: ${numbers.get(2)}")
println("Fourth element: ${numbers[3]}")
println("Index of element \"two\" ${numbers.indexOf("two")}")
MutableList
val numbers = mutableListOf(1, 2, 3, 4)
numbers.add(5)
numbers.removeAt(1)
numbers[0] = 0
numbers.shuffle()
println(numbers)