Understanding syntax for an array of tuples in Swift - arrays

I'm trying to understand syntax for arrays of tuples in Swift:
If I create a tuple:
var gameScore: (points: Int, player: String)
I can assign values like this:
gameScore = (1700, "Lisa")
And create an array of this tuple:
var gameScores = [gameScore]
I can append to the array this way:
gameScores.append((1650, "Bart"))
And this way:
gameScore = (1600, "Maggie")
gameScores += [gameScore]
But not this way:
gameScores += [(1600, "Maggie")]
Playground error is:
Playground execution failed: error: Tuples Playground.playground:38:1: error: cannot convert value of type '[(points: Int, player: String)]' to expected argument type 'inout _'
gameScores += [(1600, "Maggie")]
However, this way works:
gameScores += [(points: 1600, player: "Maggie")]
Yes – I have code above that will work, but I'm trying to figure out what I'm not understanding in the failing syntax. Elements don't need to be named for the .append() method, but they need to be named for += [()].

The Swift type inference system is being stretched to the point of breaking here. Swift is having trouble inferring the type of [(1600, "Maggie")] in your example. If you give it a little more information, your example will compile:
gameScores += [(1600, "Maggie") as (points: Int, player: String)]
gameScores += [(1600, "Maggie")] as [(points: Int, player: String)]
and
gameScores = gameScores + [(1600, "Maggie")]
all compile.
It seems Swift is having trouble inferring the type when += is involved.
Looking at the definition of +=:
func +=<C : Collection>(lhs: inout Array<C.Iterator.Element>, rhs: C)
shows that the types of the lhs and rhs are different. Swift is having trouble reconciling the types of the lhs and the rhs from the information given. It seems to be starting with the rhs and then concludes that the type of the lefthand side is inout _ and it tries to reconcile that with the type of gameScores which is [(points: Int, player: String)]. Should it be able to infer the types? Perhaps, but in this case, since you have an easy workaround, I say give the compiler a break and give it the explicit type information and make its job easier:
gameScores += [(points: 1600, player: "Maggie")]

Related

How to create an Array for Tuples in Scala?

Im trying to create an empty Array to store coordinates of an object in an Tuple which is then stored in an Array.
When I try:
var walls = Array[Tuple2]()
Im getting this error message:
kinds of the type arguments (Tuple2) do not conform to the expected kinds of the type parameters (type T).
[error] Tuple2's type parameters do not match type T's expected parameters:
[error] class Tuple2 has two type parameters, but type T has none
[error] var walls = Array[Tuple2]()
Is there any possibility to do this?
Tuple2 is a type constructor (of kind [*, *] => *).
Array is a type constructor too (of kind [*] => *).
You have to apply Tuple2 to two types (of kind *) in order to make it suitable as an argument of Array.
That's why Array[(Int, Int)] aka Array[Tuple2[Int, Int]] is working while Array[Tuple2] is not.
Okay I found a way:
var walls = Array[(Int, Int)]()

Type of expression is ambigous without more context

Im trying to make dateAndResultsDictionary and empty array of dictionaries, but i'm getting this error. What am i doing wrong?
The statement is syntactically incorrect. A dictionary can't hold more than one type of key or value so a type declaration like this:
[String: [Int], String: String]
is illegal. NB [Int] and Array<Int> are semantically identical.
If you want to hold more than one kind of thing, probably the best way is to use an enum:
enum DictionaryContent
{
case string(String)
case intArray([Int])
}
var dateAndResultDictionary = [[String: DictionaryContent]]()

How to define a zero element when using discriminated unions in F# Array functions

OK, a question, I would like to use an array of discriminated unions in the Array functions. In the code below, I define a type ResultVari that is either Unknown or a floating point value. I also define the infix plus operator for the type, which returns a value only if both args are not Unknown. This works fine.
type ResultVari =
| Unknown
| Value of float
static member (+) (a,b) = // add two ResultVari's together
match a,b with
| Value(av),Value(bv) -> Value(av + bv) // only has a value if both args do.
| _ -> Unknown
(* Summation of array of ResultVari, such that if any are unknown then the result is Unknown *)
let example1 = [| Value(4.0); Value(5.5); Value(3.1) |] // summation should be 12.6
let example2 = [| Value(4.0); Unknown; Value(3.1) |] // summation should be Unknown
let summation (varArray:ResultVari array) =
Array.sum (+) varArray //ERROR this value is not a function and cannot be applied
let summation2 (varArray:ResultVari array) =
Array.fold (+) (Value(0.0)) varArray // Works
let sum_example1 = summation2 example1
let sum_example2 = summation2 example2
printfn "%A" sum_example1 // 12.6
printfn "%A" sum_example2 // Unknown
Using summation2 the program works as expected with the sum for example1 being 12.6 and for example2 being Unknown.
But I don't understand why summation doesn't work - the compiler complains "this value is not a function and cannot be applied". In another attempt (not shown), I also got the error of a missing get_Zero element which I understand -- the sum function has to use some type of a zero definition to start the summation, and using the fold function with my Value(0.0) as the start value like in summation2 solves that.
So is there a way to define a get_Zero element for a discriminated union, or would I have to use a record type instead for ResultVari? Then I could use Array.sum instead of using Array.fold.
You need to add a zero element to use array.sum - like this:
type ResultVari =
| Unknown
| Value of float
static member (+) (a,b) = // add two ResultVari's together
match a,b with
| Value(av),Value(bv) -> Value(av + bv) // only has a value if both args do.
| _ -> Unknown
static member Zero with get() = Value(0.0)
Then the code becomes:
let summation (varArray:ResultVari array) =
Array.sum varArray
This makes sense because when you sum something you need to start from zero and without the zero member, the compiler doesn't know where to start.

What is an alternative way to convert from a tuple array type to a named tuple array type?

In Swift, [(String, Double)] and [(name: String, result: Double)] are not compatible! To convert between these to types, I can only change the type name, which is so brute force.
I mean, these two types are logically compatible, right? Just throw away the name and you get [(String, Double)]. Add the names and you get [(name: String. result: Double)].
For now, I can only loop through the array and add each item to the variable of the other type. Which is so many lines of code just to do this!
What is a more elegant way to convert between these two types?
You can use map:
let tupleArray: [(String, Double)] = [("element A", 2.5),("element B", 5.0)]
let tuppleNamedArray: [(name: String, result: Double)] = tupleArray.map{($0,$1)}
tuppleNamedArray.first?.result // 2.5
or also as suggested by vacawama:
let tuppleNamedArray = tupleArray.map{(name: $0, result: $1)}

Scala BigInt Array

I'm trying to solve this problem http://projecteuler.net/problem=62 and I am getting hung up on this error:
euler.scala:10: error: type mismatch;
found : Array[Any]
required: Array[Int]
Note: Any >: Int, but class Array is invariant in type T.
You may wish to investigate a wildcard type such as `_ >: Int`. (SLS 3.2.10)
master(perm) = if (master.contains(perm)) master(perm) :+ cube else Array(cube)
^
one error found
The problem may be because of the BigInt trying to be stored in an Array, but aparently there is no such thing as an array with Array[BigInt]
Below is my code:
import scala.util.control.Breaks._
var m = new scala.collection.mutable.LinkedHashMap[String,Array[Int]]
var master = m.withDefaultValue(Array.empty[Int])
val range = 345 to 9999
range.foreach { n =>
val cube = BigInt(n) * n * n
val perm = cube.toString.map(_.asDigit).mkString("")
master(perm) = if (master.contains(perm)) master(perm) :+ cube else Array(cube)
}
master.values.foreach { value =>
if (value.length >= 5) {
println (Math.cbrt(value(0)))
break
}
}
cube is of type BigInt. So Array(cube) is of type Array[BigInt]
The type of master(perm) is Array[Int], and you are trying to do
Array[Int] :+ BigInt => Array[Int], which does not work.
Suggestion: Make all your arrays of type BigInt.
So:
var m = new scala.collection.mutable.LinkedHashMap[String,Array[BigInt]]
var master = m.withDefaultValue(Array.empty[BigInt])
Also consider using a List, instead of an array. That :+ operator will allocate a new array each time. If you use Lists, they are smarter, will perform these immutable operations more efficiently.
There is Array[BigInt], but that is different than Array[Int]. In fact, the common supertype of BigInt and Int is Any, which is why that's appearing in your error messages: when you append cube, which is a BigInt to master(perm), which is and Array[Int], you'll get an Array which has both Int and BigInt, and the only type that supports both is Array[Any].

Resources