I'd like to create a custom Array in Kotlin.
class Node(val point: Point) {
var neighbour : Array<Node?> = Array(4, {_ -> null})
var prev : Byte = -1
}
Now, in another class, I tried to create an object like:
class OtherClass{
var field: Array<Array<Node?>> = Array(size.x, {_ -> Array(size.y, {_ -> null})})
}
So basically, I need a Grid of Nodes, all initialized with null. The provided sizes are of type Integer.
I get the following error:
Type inference failed. Expected type mismatch:
required: Array< Array< Node?>>
found: Array< Array< Nothing?>
Kotlin has an arrayOfNulls function which might make this a bit more elegant:
val field: Array<Array<Node?>> = Array(4) { arrayOfNulls<Node?>(4) }
Or, without optional types:
val field = Array(4) { arrayOfNulls<Node?>(4) }
I still have to specify Node? as the innermost type, however.
Okay, the solution was quite simple:
var field: Array<Array<Node?>> = Array(size.x, {_ -> Array(size.y, {_ -> null as Node?})})
Related
Here is a MWE:
type Obj = {n: number}
type Arr = [number] & Obj
const arr = [1] as Arr
arr.n = 1;
console.log(arr) // [1]
console.log(arr as Obj) // [1]
const b = {};
Object.assign(b, arr);
console.log(b as Obj) // {"0": 1, "n": 1}
// expected result: {n: 1}
Playground Link
In other words, when receiving a type Arr I'd like to be able to cast it to Obj.
I'm looking for an automatic cast, ie a solution only using types and high-level functions, not based on this specific type. In other words
b = {n: arr.n}
is not acceptable but I would also be pleased with something like
b = {k: arr[k] for k in Obj} // does not make sense but just to illustrate the diff with above
Some more context
In my problem the type I'm receiving (using ethers.js) is always like an array with named properties that are exactly the same as the one in the array, but with a name. In my test (using chai=4.3.4), I don't want to do
expect({n: arr.n}).to.deep.eq(expectedValue)
for each property.
For example, function signature could be
tokenMetadata(
pointer: string,
items: BigNumberish[],
overrides?: CallOverrides
): Promise<
[
string,
string,
string,
([string, string] & { trait_type: string; value: string })[]
] & {
image: string;
description: string;
name: string;
attributes: ([string, string] & { trait_type: string; value: string })[];
}
>
and the arrayish part of it just bothers me
It sounds like at runtime you want to extract the non-array properties of an augmented array so you can use them with:
expect(theObjectPartsOnly).to.deep.eq(expectedValue)
...without having to write each one out individually:
// Not like this:
expect({x: arr.x}).to.deep.eq(expectedValue)
expect({y: arr.y}).to.deep.eq(expectedValue)
expect({z: arr.z}).to.deep.eq(expectedValue)
Since the type of the object probably isn't important at that point, I think I'd probably not worry about the TypeScript part and just handle it at the runtime level, something like this:
const rexDigits = /^\d+$/;
const check = Object.fromEntries(
Object.entries(arr).filter(([key]) => !rexDigits.test(key))
);
expect(check).to.deep.equal(expectedValue);
That filters out the array index properties (roughly speaking, that's not an exact match for the definition of an array index but it's probably good enough for our purposes here) before doing the to.deep.equal check.
I need to perform binary search on an array of custom case class. This should be as simple as calling the search function defined in scala.collection.Searching:
As you can see, if the collection on which I call the search method is an indexed sequence, the binary search is performed.
Now, I need to create my custom Ordering[B] parameter and I want to pass it explicitly to the search function (I don't want for it to take any implicit parameter inferred from context).
I have the following code:
// File 1
case class Person(name: String, id: Int)
object Person{
val orderingById: Ordering[Person] = Ordering.by(e => e.id)
}
// File 2 (same package)
for(i <- orderedId.indices) {
// orderedId is an array of Int
// listings is an array of Person
val listingIndex = listings.search(orderedId(i))(Person.orderingById)
...
}
I get the following error:
Type mismatch. Required: Ordering[Any], found: Ordering[Nothing]
So, I tried change the implementation in this way:
// file 1
object Person{
implicit def orderingById[A <: Person] : Ordering[A] = {
Ordering.by(e => e.id)
}
}
//file 2 as before
This time getting the following error:
Type mismatch. Required: Ordering[Any], found: Ordering[Person]
Why does it happen? At least in the second case, should it convert from Any to Person?
Follow the type specifications.
If you want to .search() on a collection of Person elements then the first search parameter should be a Person (or a super-class thereof).
val listingIndex =
listings.search(Person("",orderedId(i)))(Person.orderingById)
Or, to put it in a more complete and succinct context:
import scala.collection.Searching.SearchResult
case class Person(name: String, id: Int)
val listings: Array[Person] = ...
val orderedId: Array[Int] = ...
for(id <- orderedId) {
val listingIndex: SearchResult =
listings.search(Person("",id))(Ordering.by(_.id))
}
I'll add a bit just to elaborate about your error. First, please note that Searching.search is deprecated, with deprecation message:
Search methods are defined directly on SeqOps and do not require scala.collection.Searching any more.
search is now defined on IndexedSeqOps. Let's look at the signature:
final def search[B >: A](elem: B)(implicit ord: Ordering[B])
When you call:
listings.search(orderedId(i))(Person.orderingById)
The result of orderedId(i) is Int. Therefore, B in the signature above is Int. The definition of Int is:
final abstract class Int private extends AnyVal
A is Person, because listing is of type Array[Person]. Therefore, search, is looking for a common root for both Int and Person. This common root is Any, hence you are getting this error. One way to overcome it, is to define an implicit conversion from Int to Person:
object Person{
val orderingById: Ordering[Person] = Ordering.by(e => e.id)
implicit def apply(id: Int): Person = {
Person("not defined", id)
}
}
Then the following:
val listings = Array(Person("aa", 1), Person("bb", 2), Person("dd", 4))
val orderedId = 1.to(6).toArray
for(i <- orderedId.indices) {
// orderedId is an array of Int
// listings is an array of Person
listings.search[Person](orderedId(i))(Person.orderingById) match {
case Found(foundIndex) =>
println("foundIndex: " + foundIndex)
case InsertionPoint(insertionPoint) =>
println("insertionPoint: " + insertionPoint)
}
}
will produce:
foundIndex: 0
foundIndex: 1
insertionPoint: 2
foundIndex: 2
insertionPoint: 3
insertionPoint: 3
Code run in Scastie.
Apologies if this is trivial, but I have not yet gotten my head around KeyPaths fully. I have a class (ContainerClass) which has an array of classes in it (mySettings). the mySettings Class has two variables (color and name). The array of mySettings is defined at runtime. I am trying to modify the properties in the mySettings class via KeyPaths. The following code is a simplified version of what I am trying to achieve:
import Cocoa
import Foundation
class Settings {
var color: Int?
var name: String?
init(color: Int, name: String) {
self.color = color
self.name = name
}
}
class ContainerClass {
var mySettings = [Settings]()
}
var myClass = ContainerClass()
let kp = \ContainerClass.mySettings
let kp2 = [\Settings.color, \Settings.name]
myClass.mySettings.append(Settings(color: 1, name: "One"))
myClass.mySettings.append(Settings(color: 2, name: "Two"))
myClass.mySettings.append(Settings(color: 3, name: "Three"))
myClass.mySettings.append(Settings(color: 4, name: "Four"))
myClass.mySettings.append(Settings(color: 5, name: "Five"))
for index in 0..<myClass.mySettings.count {
print(myClass.mySettings[index].color!)
}
let target = myClass[keyPath: kp][0][keyPath: kp2[0]]
print("\ntarget:", target as! Int)
myClass[keyPath: kp][0][keyPath: kp2[0]] = 128 // ERROR: Cannot assign through subscript: 'myClass' is immutable
for index in 0..<myClass.mySettings.count {
print(myClass.mySettings[index].color!)
}
I need two separate KeyPaths: one to target one specific mySettings element of the array contained in ContainerClass, and another KeyPath to target one of the two properties within the Settings class. At runtime, the program will determine which element of the array and which property must be modified.
I can read the property (in my example via: let target = myClass[keyPath: kp][0][keyPath: kp2[0]]), but I cannot modify it by trying, for example, a line like: myClass[keyPath: kp][0][keyPath: kp2[0]] = 128. I get an error: Cannot assign through subscript: 'myClass' is immutable.
I am not sure about the interaction of these partial keypaths with arrays. Any help on how to resolve this (i.e. being able to modify properties within Settings this way) will be much appreciated.
I have a problem concerning my nested dictionary.
var level1Dictionary = [String : [String : String]]()
var ChosenDeckLabel = [String]
textview.text
I want to see if the dictionary contains a certain value within my, else if statement as such:
else if level1Dictionary[ChosenDeckLabel[textview.text]] != nil {
this returns error:
Cannot subscript value of type String with an index of type String!
How should I cast it to check if the nested dictionary contains the value?
Dictionaries are optionals by default because they are not sure if a key/value pair exist. Be sure to include your "!" AND "?" to wrap and unwrap your data being passed.
Arrays offer subscripting via integers and ranges as seen in Swift's API:
public subscript (index: Int) -> Element
public subscript (subRange: Range<Int>) -> ArraySlice<Element>
You're trying to subscript via a string which is throwing the error. You need to get the index of the element in the array and then use that to subscript the array to get the value: e.g.
let dictOfDicts = [String : [String : String]]()
var arrayOfStrings: [String] = ["a", "b", "c"]
let stringToCheck = "a"
dictOfDicts["a"] = ["some": "thing"]
if let index = array.indexOf(stringToCheck) {
if dictOfDicts[array[Int(index)]] != nil {
// do something
}
}
I think this is what you intend to do:
else if level1Dictionary[strIndex1][strIndex2] != nil {
When you are doing this:
level1Dictionary[ChosenDeckLabel[textview.text]]
you are trying to access the ChosenDeckLabel array using a String subscript:
ChosenDeckLabel[textview.text]
which is not a valid operation. Arrays are Int indexed and not string indexed.
I am new to Swift.
I am trying to get some data from a webservice and to loop the JSON data to make a simple array.
DataManager.getDataFromEndpoint{ (endpointData) -> Void in
let json = JSON(data: endpointData)
if let programsOnAir = json["data"]["data"]["on_air"].array{
var onAirArray = []
for onAir in programsOnAir {
var eventName = onAir["event_name"].string
var eventCover = onAir["event_cover"].string
var tuple = (name: eventName!, cover: eventCover!)
onAirArray.insert(tuple, atIndex: 1)
}
println(onAirArray)
}
}
I get an error where the member .insert does not exist
BUt if I init the array like this var onAirArray = [name: "something, cover: "somethingelse"] then it works.
I need to work with empty arrays and I need to be them mutable, because I have no idea what I may get from the JSON given by the API endpoint.
What am I doing wrong?
The problem is with this line:
var onAirArray = []
Since you haven't given the array an explicit type, this is creating a new instance of NSArray, which doesn't have a method called insert. Which is why this is probably the exact error message you're receiving.
'NSArray' does not have a member named 'insert'
To fix this, explicitly state the type of your array.
var onAirArray: [(String, String)] = []