Create generic 2D array in Kotlin - arrays

Suppose I have a generic class and I need a 2D array of generic type T. If I try the following
class Matrix<T>(width: Int, height: Int) {
val data: Array<Array<T>> = Array(width, arrayOfNulls<T>(height))
}
the compiler will throw an error saying "Cannot use 'T' as reified type parameter. Use a class instead.".

Just because the syntax has moved on a bit, here's my take on it:
class Array2D<T> (val xSize: Int, val ySize: Int, val array: Array<Array<T>>) {
companion object {
inline operator fun <reified T> invoke() = Array2D(0, 0, Array(0, { emptyArray<T>() }))
inline operator fun <reified T> invoke(xWidth: Int, yWidth: Int) =
Array2D(xWidth, yWidth, Array(xWidth, { arrayOfNulls<T>(yWidth) }))
inline operator fun <reified T> invoke(xWidth: Int, yWidth: Int, operator: (Int, Int) -> (T)): Array2D<T> {
val array = Array(xWidth, {
val x = it
Array(yWidth, {operator(x, it)})})
return Array2D(xWidth, yWidth, array)
}
}
operator fun get(x: Int, y: Int): T {
return array[x][y]
}
operator fun set(x: Int, y: Int, t: T) {
array[x][y] = t
}
inline fun forEach(operation: (T) -> Unit) {
array.forEach { it.forEach { operation.invoke(it) } }
}
inline fun forEachIndexed(operation: (x: Int, y: Int, T) -> Unit) {
array.forEachIndexed { x, p -> p.forEachIndexed { y, t -> operation.invoke(x, y, t) } }
}
}
This also allows you to create 2d arrays in a similar manner to 1d arrays, e.g. something like
val array2D = Array2D<String>(5, 5) { x, y -> "$x $y" }
and access/set contents with the indexing operator:
val xy = array2D[1, 2]

The problem is calling arrayOfNulls<T>(height) with the non-reified type parameter T. But we also can't make T reified, the compiler will throw the following error: "Only type parameters of inline functions can be reified"
So that's what we're going to do. Instead of the constructor we use an inlined factory method:
class Matrix<T> private(width: Int, height: Int, arrayFactory: (Int) -> Array<T>) {
class object {
inline fun <reified T>invoke(width: Int, height: Int)
= Matrix(width, height, { size -> arrayOfNulls<T>(size) })
}
val data: Array<Array<T>> = Array(width, { size -> arrayFactory(size) })
}
Notice, the constructor is now private, so calling Matrix() will correctly call the new invoke() method (related question). Because the method is inlined, we can use reified generics which makes it possible to call arrayOfNulls<T>.

Related

Swift array map without $0 (Higher-Order Functions )

I have a function that generates a number with some conditions
func randomWithCondition() -> Int {
...
return n
}
And later I will use this function to build an array with N length in another function
func a() -> [Int] {
var arr = [Int]()
for _ in 0..<length {
arr.append(randomWithCondition())
}
return arr
}
I want to write those in one line, the best thing I can think of is
return (0..<N).map { _ in randomWithCondition() }
I have to add _ in because I didn't use $0, otherwise it won't compile.
Question: Is there a walk round to not write _ in? any other format would be fine as long as it's one line in the return statement.
map transforms each element from its type to other so that the transformation requires the parameter in the closure. But for convenience you can omit this parameter by making extensions for Range and ClosedRange:
extension Range where Bound: Strideable, Bound.Stride: SignedInteger {
public func map<T>(_ transform: () -> T) -> [T] {
map { _ in transform() }
}
}
extension ClosedRange where Bound: Strideable, Bound.Stride: SignedInteger {
public func map<T>(_ transform: () -> T) -> [T] {
map { _ in transform() }
}
}
let range = (0..<10).map { arc4random() }
print(range)
// Outputs: [676946806, 482060909, 1553829324, 1660236508, 606395000, 268649066, 1438948568, 1995527535, 918698113, 505678702]
let closedRange = (0...9).map { arc4random() }
print(closedRange)
// Outputs: [20467139, 198204705, 1585520963, 2022302907, 2518334206, 3304761403, 3782378335, 3830286797, 2200585433, 2387902936]
You need to define some extra functions yourself.
For example, a const function (name is inspired by Haskell, but you can call it withParameter instead):
func const<T, U>(_ f: #escaping () -> U) -> ((T) -> U) {
{ _ in f() }
}
Then you can do:
return (0..<N).map(const(randomWithCondition))
I think you should also wrap this in a generate function:
func generate<T>(_ count: Int, generator: #escaping () -> T) -> [T] {
(0..<count).map(const(generator))
}
Do note that you can also create lazy infinite sequences with sequence, rather than mapping a range.

Create copy of generic array with new size

Is it possible in Kotlin to create a copy of a generic array with new size if I already have an instance of that array and pass a construction method for its items? I think about something like this:
fun <T> resize(arr: Array<T>, newSize: Int, creator: (Int) -> T): Array<T> {
...
}
Obviously I cannot call Array<T>(newSize) { i -> creator(i) } because the type T is not known at compile time. For efficicy reasons I do not want to use an inline function with a reified type. I also cannot use the arr.copyOf(newSize) method here because that would return an Array<T?>.
In Java I could use Arrays.copyOf(arr, newSize) even with a generic array because we don't have null safety here. But would this work in Kotlin as well? Or do you have any other ideas what I could do?
I would just add an extension method to Array<T> for this. You can still rely on Arrays.copyOf under the hood, but before returning the value fill any remaining spaces with the result of the creator block:
fun <T> Array<T>.resize(newSize: Int, creator: (Int) -> T): Array<T> {
val copiedArray = Arrays.copyOf(this, newSize)
for (i in size until newSize) { copiedArray[i] = creator(i) }
return copiedArray
}
For example:
val array = arrayOf("a", "b", "c")
// same: [a, b, c]
println("same: ${Arrays.toString(array.resize(3) { it.toString() })}")
// less: [a, b]
println("less: ${Arrays.toString(array.resize(2) { it.toString() })}")
// more: [a, b, c, 3, 4]
println("more: ${Arrays.toString(array.resize(5) { it.toString() })}")
I guess this will work:
fun <T> resize(arr: Array<T>, dest: Array<T>, creator: (Int) -> T): Array<T> {
val list = arrayListOf<T>()
// fill the list
for (i in 0 until dest.size) {
list.add(creator(i))
}
return list.toArray(dest)
}
fun callResize() {
val arr = Array(5) { " " }
val dest = Array(10) { "" }
val creator = { i: Int -> "$i"}
resize(arr, dest, creator)
}
The result is in the dest array.

Generic function with generic 2D array

How can one implement a generic function which creates an empty generic 2D array? In the following code sample an empty 1D array is created and has the expected type. However, when I call test2D I get an error:
java.lang.ClassCastException: [[Ljava.lang.Object; cannot be cast to [[Ljava.lang.Integer;
inline fun <reified T> make1D(mask: Array<T>) : Array<T> {
val res : Array<T> = arrayOf()
return res
}
#Test
fun test1D() {
val a : Array<Int> = arrayOf(0)
val b : Array<Int> = make1D(a)
assertEquals(0, b.size)
}
inline fun <reified T> make2D(mask: Array<Array<T>>) : Array<Array<T>> {
val res : Array<Array<T>> = arrayOf()
// I expect T to be equal to Int when calling from test below,
// and res to have Integer[][] type;
// however it has Object[][] type instead
return res
}
#Test
fun test2D() {
val a : Array<Array<Int>> = arrayOf(arrayOf(0))
val b : Array<Array<Int>> = make2D(a)
assertEquals(0, b.size)
}
I think you are one level too deep for the reified parameter. Maybe it is a bug, creating a YouTrack issue will help to find out. This code works when you let T be the whole inner array:
inline fun <reified T> make2D(mask: Array<T>): Array<T> {
val res: Array<T> = arrayOf<T>()
return res
}
#Test
fun test2D() {
val a: Array<Array<Int>> = arrayOf(arrayOf(0))
val b: Array<Array<Int>> = make2D(a)
assertEquals(0, b.size)
}
After you create a YouTrack issue, please post the issue number here for tracking.

Insert generic object into array swift [duplicate]

How can I extend Swift's Array<T> or T[] type with custom functional utils?
Browsing around Swift's API docs shows that Array methods are an extension of the T[], e.g:
extension T[] : ArrayType {
//...
init()
var count: Int { get }
var capacity: Int { get }
var isEmpty: Bool { get }
func copy() -> T[]
}
When copying and pasting the same source and trying any variations like:
extension T[] : ArrayType {
func foo(){}
}
extension T[] {
func foo(){}
}
It fails to build with the error:
Nominal type T[] can't be extended
Using the full type definition fails with Use of undefined type 'T', i.e:
extension Array<T> {
func foo(){}
}
And it also fails with Array<T : Any> and Array<String>.
Curiously Swift lets me extend an untyped array with:
extension Array {
func each(fn: (Any) -> ()) {
for i in self {
fn(i)
}
}
}
Which it lets me call with:
[1,2,3].each(println)
But I can't create a proper generic type extension as the type seems to be lost when it flows through the method, e.g trying to replace Swift's built-in filter with:
extension Array {
func find<T>(fn: (T) -> Bool) -> T[] {
var to = T[]()
for x in self {
let t = x as T
if fn(t) {
to += t
}
}
return to
}
}
But the compiler treats it as untyped where it still allows calling the extension with:
["A","B","C"].find { $0 > "A" }
And when stepped-thru with a debugger indicates the type is Swift.String but it's a build error to try access it like a String without casting it to String first, i.e:
["A","B","C"].find { ($0 as String).compare("A") > 0 }
Does anyone know what's the proper way to create a typed extension method that acts like the built-in extensions?
For extending typed arrays with classes, the below works for me (Swift 2.2). For example, sorting a typed array:
class HighScoreEntry {
let score:Int
}
extension Array where Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0.score < $1.score }
}
}
Trying to do this with a struct or typealias will give an error:
Type 'Element' constrained to a non-protocol type 'HighScoreEntry'
Update:
To extend typed arrays with non-classes use the following approach:
typealias HighScoreEntry = (Int)
extension SequenceType where Generator.Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0 < $1 }
}
}
In Swift 3 some types have been renamed:
extension Sequence where Iterator.Element == HighScoreEntry
{
// ...
}
After a while trying different things the solution seems to remove the <T> from the signature like:
extension Array {
func find(fn: (T) -> Bool) -> [T] {
var to = [T]()
for x in self {
let t = x as T;
if fn(t) {
to += t
}
}
return to
}
}
Which now works as intended without build errors:
["A","B","C"].find { $0.compare("A") > 0 }
Extend all types:
extension Array where Element: Any {
// ...
}
Extend Comparable types:
extension Array where Element: Comparable {
// ...
}
Extend some types:
extension Array where Element: Comparable & Hashable {
// ...
}
Extend a particular type:
extension Array where Element == Int {
// ...
}
I had a similar problem - wanted to extend the general Array with a swap() method, which was supposed to take an argument of the same type as the array. But how do you specify the generic type? I found by trial and error that the below worked:
extension Array {
mutating func swap(x:[Element]) {
self.removeAll()
self.appendContentsOf(x)
}
}
The key to it was the word 'Element'. Note that I didn't define this type anywhere, it seems automatically exist within the context of the array extension, and refer to whatever the type of the array's elements is.
I am not 100% sure what's going on there, but I think it is probably because 'Element' is an associated type of the Array (see 'Associated Types' here https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-ID189)
However, I can't see any reference of this in the Array structure reference (https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Array_Structure/index.html#//apple_ref/swift/struct/s:Sa)... so I'm still a little unsure.
Using Swift 2.2:
I ran into a similar issue when trying to remove duplicates from an array of strings. I was able to add an extension on the Array class that does just what I was looking to do.
extension Array where Element: Hashable {
/**
* Remove duplicate elements from an array
*
* - returns: A new array without duplicates
*/
func removeDuplicates() -> [Element] {
var result: [Element] = []
for value in self {
if !result.contains(value) {
result.append(value)
}
}
return result
}
/**
* Remove duplicate elements from an array
*/
mutating func removeDuplicatesInPlace() {
var result: [Element] = []
for value in self {
if !result.contains(value) {
result.append(value)
}
}
self = result
}
}
Adding these two methods to the Array class allows me to call one of the two methods on an array and successfully remove duplicates. Note that the elements in the array must conform to the Hashable protocol. Now I can do this:
var dupes = ["one", "two", "two", "three"]
let deDuped = dupes.removeDuplicates()
dupes.removeDuplicatesInPlace()
// result: ["one", "two", "three"]
If you want to learn about extending Arrays and other types of build in classes checkout code in this github repo https://github.com/ankurp/Cent
As of Xcode 6.1 the syntax to extend arrays is as follows
extension Array {
func at(indexes: Int...) -> [Element] {
... // You code goes herer
}
}
I had a look at the Swift 2 standard library headers, and here is the prototype for the filter function, which makes it quite obvious how to roll your own.
extension CollectionType {
func filter(#noescape includeElement: (Self.Generator.Element) -> Bool) -> [Self.Generator.Element]
}
It's not an extension to Array, but to CollectionType, so the same method applies to other collection types. #noescape means that the block passed in will not leave the scope of the filter function, which enables some optimisations. Self with a capital S is the class we are extending. Self.Generator is an iterator that iterates through the objects in the collection and Self.Generator.Element is the type of the objects, for example for an array [Int?] Self.Generator.Element would be Int?.
All in all this filter method can be applied to any CollectionType, it needs a filter block which takes an element of the collection and returns a Bool, and it returns an array of the original type. So putting this together, here's a method that I find useful: It combines map and filter, by taking a block that maps a collection element to an optional value, and returns an array of those optional values that are not nil.
extension CollectionType {
func mapfilter<T>(#noescape transform: (Self.Generator.Element) -> T?) -> [T] {
var result: [T] = []
for x in self {
if let t = transform (x) {
result.append (t)
}
}
return result
}
}
import Foundation
extension Array {
var randomItem: Element? {
let idx = Int(arc4random_uniform(UInt32(self.count)))
return self.isEmpty ? nil : self[idx]
}
}
(Swift 2.x)
You can also extend the array to conform to a protocol containing blue-rpints for generic type methods, e.g., a protocol containing your custom functional utils for all generic array elements conforming to some type constraint, say protocol MyTypes. The bonus using this approach is that you can write functions taking generic array arguments, with a constraint that these array arguments must conform to your custom function utilities protocol, say protocol MyFunctionalUtils.
You can get this behaviour either implicitly, by type constraining the array elements to MyTypes, or---as I will show in the method I describe below---, quite neatly, explicitly, letting your generic array functions header directly show that input arrays conforms to MyFunctionalUtils.
We begin with Protocols MyTypes for use as type constraint; extend the types you want to fit in your generics by this protocol (example below extends fundamental types Int and Double as well as a custom type MyCustomType)
/* Used as type constraint for Generator.Element */
protocol MyTypes {
var intValue: Int { get }
init(_ value: Int)
func *(lhs: Self, rhs: Self) -> Self
func +=(inout lhs: Self, rhs: Self)
}
extension Int : MyTypes { var intValue: Int { return self } }
extension Double : MyTypes { var intValue: Int { return Int(self) } }
// ...
/* Custom type conforming to MyTypes type constraint */
struct MyCustomType : MyTypes {
var myInt : Int? = 0
var intValue: Int {
return myInt ?? 0
}
init(_ value: Int) {
myInt = value
}
}
func *(lhs: MyCustomType, rhs: MyCustomType) -> MyCustomType {
return MyCustomType(lhs.intValue * rhs.intValue)
}
func +=(inout lhs: MyCustomType, rhs: MyCustomType) {
lhs.myInt = (lhs.myInt ?? 0) + (rhs.myInt ?? 0)
}
Protocol MyFunctionalUtils (holding blueprints our additional generic array functions utilities) and thereafter, the extension of Array by MyFunctionalUtils; implementation of blue-printed method(s):
/* Protocol holding our function utilities, to be used as extension
o Array: blueprints for utility methods where Generator.Element
is constrained to MyTypes */
protocol MyFunctionalUtils {
func foo<T: MyTypes>(a: [T]) -> Int?
// ...
}
/* Extend array by protocol MyFunctionalUtils and implement blue-prints
therein for conformance */
extension Array : MyFunctionalUtils {
func foo<T: MyTypes>(a: [T]) -> Int? {
/* [T] is Self? proceed, otherwise return nil */
if let b = self.first {
if b is T && self.count == a.count {
var myMultSum: T = T(0)
for (i, sElem) in self.enumerate() {
myMultSum += (sElem as! T) * a[i]
}
return myMultSum.intValue
}
}
return nil
}
}
Finally, tests and two examples showing a function taking generic arrays, with the following cases, respectively
Showing implicit assertion that the array parameters conform to protocol 'MyFunctionalUtils', via type constraining the arrays elements to 'MyTypes' (function bar1).
Showing explicitly that the array parameters conform to protocol 'MyFunctionalUtils' (function bar2).
The test and examples follows:
/* Tests & examples */
let arr1d : [Double] = [1.0, 2.0, 3.0]
let arr2d : [Double] = [-3.0, -2.0, 1.0]
let arr1my : [MyCustomType] = [MyCustomType(1), MyCustomType(2), MyCustomType(3)]
let arr2my : [MyCustomType] = [MyCustomType(-3), MyCustomType(-2), MyCustomType(1)]
/* constrain array elements to MyTypes, hence _implicitly_ constraining
array parameters to protocol MyFunctionalUtils. However, this
conformance is not apparent just by looking at the function signature... */
func bar1<U: MyTypes> (arr1: [U], _ arr2: [U]) -> Int? {
return arr1.foo(arr2)
}
let myInt1d = bar1(arr1d, arr2d) // -4, OK
let myInt1my = bar1(arr1my, arr2my) // -4, OK
/* constrain the array itself to protocol MyFunctionalUtils; here, we
see directly in the function signature that conformance to
MyFunctionalUtils is given for valid array parameters */
func bar2<T: MyTypes, U: protocol<MyFunctionalUtils, _ArrayType> where U.Generator.Element == T> (arr1: U, _ arr2: U) -> Int? {
// OK, type U behaves as array type with elements T (=MyTypes)
var a = arr1
var b = arr2
a.append(T(2)) // add 2*7 to multsum
b.append(T(7))
return a.foo(Array(b))
/* Ok! */
}
let myInt2d = bar2(arr1d, arr2d) // 10, OK
let myInt2my = bar2(arr1my, arr2my) // 10, OK
import Foundation
extension Array {
func calculateMean() -> Double {
// is this an array of Doubles?
if self.first is Double {
// cast from "generic" array to typed array of Doubles
let doubleArray = self.map { $0 as! Double }
// use Swift "reduce" function to add all values together
let total = doubleArray.reduce(0.0, combine: {$0 + $1})
let meanAvg = total / Double(self.count)
return meanAvg
} else {
return Double.NaN
}
}
func calculateMedian() -> Double {
// is this an array of Doubles?
if self.first is Double {
// cast from "generic" array to typed array of Doubles
var doubleArray = self.map { $0 as! Double }
// sort the array
doubleArray.sort( {$0 < $1} )
var medianAvg : Double
if doubleArray.count % 2 == 0 {
// if even number of elements - then mean average the middle two elements
var halfway = doubleArray.count / 2
medianAvg = (doubleArray[halfway] + doubleArray[halfway - 1]) / 2
} else {
// odd number of elements - then just use the middle element
medianAvg = doubleArray[doubleArray.count / 2 ]
}
return medianAvg
} else {
return Double.NaN
}
}
}
Extention Array Find Index:
extension Array where Element: Equatable {
func findElementArrayIndex(findElement: String) -> Int {
var indexValue: Int = 0
var search = self.filter { findElement.isEmpty || "\($0)".contains(findElement)}
//print("search: \(search)")
for i in 0..<self.count {
if self[i] == search[0] {
indexValue = i
break
}
}
return indexValue
}
}

How can I check for generic type in Kotlin

I'm trying to test for a generic type in Kotlin.
if (value is Map<String, Any>) { ... }
But the compiler complains with
Cannot check for instance of erased type: jet.Map
The check with a normal type works well.
if (value is String) { ... }
Kotlin 0.4.68 is used.
What am I missing here?
The problem is that type arguments are erased, so you can't check against the full type Map, because at runtime there's no information about those String and Any.
To work around this, use wildcards:
if (value is Map<*, *>) {...}
I think this is more appropriate way
inline fun <reified T> tryCast(instance: Any?, block: T.() -> Unit) {
if (instance is T) {
block(instance)
}
}
Usage
// myVar is nullable
tryCast<MyType>(myVar) {
// todo with this e.g.
this.canDoSomething()
}
Another shorter approach
inline fun <reified T> Any?.tryCast(block: T.() -> Unit) {
if (this is T) {
block()
}
}
Usage
// myVar is nullable
myVar.tryCast<MyType> {
// todo with this e.g.
this.canDoSomething()
}
JVM removes the generic type information. But Kotlin has reified generics. If you have a generic type T, you can mark type parameter T of an inline function as reified so it will be able to check it at runtime.
So you can do:
inline fun <reified T> checkType(obj: Object, contract: T) {
if (obj is T) {
// object implements the contract type T
}
}
I'm gonna give a workaround solution but I think its clean, kind of
try{
(value as Map<String,Any>?)?.let { castedValue ->
doYourStuffHere() //using castedValue
}
}catch(e: Exception){
valueIsNotOfType() //Map<String,Any>
}
Here's what I use:
// Use this value if it is of type T, or else use defaultValue
inline fun <reified T> Any?.useIfTypeOrDefault(defaultValue: T) =
if (this is T) this else defaultValue
Usage (kotest):
val map = mapOf("foo" to listOf("cheese"), "bar" to 666)
map["foo"].useIfTypeOrDefault<List<String>>(emptyList()).firstOrNull() shouldBe "cheese"
map["bar"].useIfTypeOrDefault<List<String>>(emptyList()).firstOrNull() shouldBe null
map["foo"].useIfTypeOrDefault<Number>(-1) shouldBe -1
map["bar"].useIfTypeOrDefault<Number>(-1) shouldBe 666
I have tried the solution above with tryCast<Array<String?>> and, I guess, in my specific task in listing with many castings involved it was no so great idea, because it was slowing the performance drastically.
This is the solution I did finally - manually check the entries and call methods, like this:
fun foo() {
val map: Map<String?, Any?> = mapOf()
map.forEach { entry ->
when (entry.value) {
is String -> {
doSomeWork(entry.key, entry.value as String)
}
is Array<*> -> {
doSomeWork(entry.key, (entry.value as? Array<*>)?.map {
if (it is String) {
it
} else null
}?.toList())
}
}
}
}
private fun doSomeWork(key: String?, value: String) {
}
private fun doSomeWork(key: String?, values: List<String?>?) {
}

Resources