I trying to compose and initialize an Array in a single line, roughly equivalent to this:
var characterMap = new Array[List[ActorRef]](sizeX*sizeY)
characterMap.indices.foreach(characterMap(_) = Nil)
This doesn't seem to work:
var characterMap = ((0 until sizeX*sizeY) map Nil).toArray[List[ActorRef]]
But this does:
var characterMap = (for (_ <- 0 until sizeX*sizeY) yield Nil).toArray[List[ActorRef]]
I thought they were equivalent?
var characterMap = (for (_ <- 0 until sizeX*sizeY) yield Nil).toArray[List[ActorRef]]
Is translated into:
var characterMap = (0 until sizeX*sizeY).map(_ => Nil).toArray[List[ActorRef]]
and this should work.
Nit-picking: They are not equivalent, they are the same. for is just sugar syntax.
By the way, you might want to consider:
Array.fill[List[ActorRef]](sizeX*sizeY)(Nil)
To clarify a bit why your code wasn't working, and what it was actually doing.
val characterMap = ((0 until 10) map Nil)
I've simplified a bit to make it more comprehensible.
(0 until 10) is a Range object whose map method (as for others collections and such) expects a function of type (A) => B
where A = Int in our case
Since the typechecker is satisfied with map Nil, it looks like Nil must be a function (Int) => B in some way, could it be?
The point here is that Nil(i: Int) can be used as syntax sugar for Nil.apply(i: Int) which actually exists!
It's the generic sequential collection method to get the i-th element.
Running the above code tries to convert the range elements (0,1,...,9) to the corresponding indexed values of the Nil object, which is the empty List
Of course there's no element in the empty list, so an error is thrown, as shown
scala> val characterMap = ((0 until 10) map Nil)
java.lang.IndexOutOfBoundsException: 0
at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:52)
at scala.collection.immutable.List.apply(List.scala:84)
at scala.collection.immutable.List.apply(List.scala:84)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.Range.foreach(Range.scala:141)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
...
conclusion
yield and map have the same semantic meaning but slightly different syntactical rules.
While yield expects the result of the mapped function, map expects the function itself.
Another unexpected subtlety of the language which can take us by surprise while we're still not totally familiar with it.
Related
Why does reducing an array into a hash with the keys as array values and the value as nil give an empty result?
[1,2,3].reduce(into: [Int:Int?](), { $0[$1] = nil })
[1,2,3].reduce(into: [Int:Int?](), { $0[$1] = 1 })
Both of these should have 3 entries, right?
In Swift, setting a dictionary value to nil like you did in the question removes that value from the dictionary entirely. However there are some odd caveats to this.
In your example, you use a Dictionary with type [Int:Int?]:
var dictionary: [Int:Int?] = [1: 1, 2: 1, 3: 1]
Setting a value to nil in the following way removes it:
dictionary[1] = nil
Setting a value to nil with type Int? will assign nil instead:
dictionary[1] = nil as Int?
Likewise, using the updateValue(_:forKey:) function will do the same:
dictionary.updateValue(nil, forKey: 1)
Printing the dictionary after performing either of these operations would show the following:
[1: nil, 2: Optional(1), 3: Optional(1)]
So the behavior is a bit odd but it is possible to achieve your intended result. I don't really recommend it because of how unnatural it is; it is possible, though.
The behaviour is not at all odd actually, and it's a really natural outcome if you understand some fundamental features of Swift's dictionaries and optionals.
Nested optionals
Firstly, optionals are composable. You can have nested optionals, like Optional<Optional<Int>> (a.k.a. Int??). A nested optional like this has possible three values. To illustrate their difference, imagine the result of array.first, where array has type Array<Optional<Optional<Int>>:
Optional.some(Optional.some(someWrappedValue)), which is just the "non-nil" case, with a payload of someWrappedValue. In the context of array.first, that means the array is non-empty, and the first element is non-nil value someWrappedValue (of type Int).
Optional.some(Optional.none), which is a non-nil optional containing a nil. In the context of array.first, that means ten array is non-empty, and the first element is itself nil.
Optional.none, which is just a nil optional. In the context of array.first, that means the array is empty, and there is no first element.
Note the different between case 2 and case 3. "Where" the nil is "found" along the chain has a semantic difference. Optional.none (a.k.a. nil) means there are no elements, which is semantically different to Optional.some(Optional.none), which means there are elements, but the first of them is actually nil.
The precise meaning of nil
Secondly, nil is a shorthand for Optional<T>.none, where T is inferred from the context. For example, that's why let x = nil is illegal, because the type inference system has no clues as to what value of T is appropriate.
Note that nil on its own is inferred to a none at the "earliest" ("outermost") level of optionality. (Case 3, in the list above)
Assign nil through a dictionary subscript
Thirdly, assigning nil to a Dictionary through a subscript erases the value for the given key.
Putting it together
Given these three points, we can consider your example. The subscript of a dictionary is "one layer more optional" than the Value generic type of the dictionary. E.g. for a dict of type [Int: Int], the return type of the subscript operator is V?, and correspondingly, you can assign Int?.
Now consider your dictionary, of type [Int: Int?]. The subscript takes/returns an Int??. Let's consider the three possible cases in context, as before:
Assigning a value of type Optional.some(Optional.some(someWrappedValue)) makes the dict store a value of someWrappedValue for the key, as an Int?. This is what's happening when you write $0[$1] = 1 (Swift is implicitly promoting 1 to Optional.some(Optional.some(1)).
Assigning a value of type Optional.some(Optional.none) makes the dict store a value of nil for the key, as an Int?. This is the part you were missing.
Assigning a value of type Optional.none makes the dict erase any value that might have existed for the key. This is what's happening when you write $0[$1] = nil
So to make this code give your designed outcome, you need to supply a value of the second type. You can do this with:
[1,2,3].reduce(into: [Int:Int?]()) { $0[$1] = Optional.some(nil) }
I am learning Scala and tried practising some examples on Arrays. Below is the example:
scala>var arr = Array(Array(1,2,3), Array(4,5,6));
scala>arr.map(_.map(_ * 5))
res42: Array[Array[Int]] = Array(Array(5,10,15),Array(20,25,30))
When I tried doing the filter method the on above mentioned array in the same way, it resulted in an error. Below is the piece of code and the resulting error.
scala>arr.filter(_.filter(_ < 5))
<console>:15: error: type mismatch;
found : Array[Int]
required: Boolean
o.filter(_.filter(_ < 5))
^
Please tell why the filter operation isn't working what is the correct way to use the filter method on an array of Arrays ?
If the objective is to get Array(Array(1,2,3), Array(4)), then
arr.map(_.filter(_ < 5))
If the objective is to get Array(1,2,3,4), then
arr.flatten.filter(_ < 5)
First of all, you should read a good book if you're interested in Scala. Using vars is a very bad practice and should be avoided by beginners.
About your example, just to explain why it fails, filter requires as parameter a function with return type Boolean. In the inner filter you correctly use _ < 5 which is expanded to (x: Int) => x < 5, a function that returns true or false. But on the outer filter you used _.filter(_ < 5) which is expanded to (y: Array[Int]) => y.filter((x: Int) => x < 5). Here's the issue, y.filter((x: Int) => x < 5) will return a new Array, which means the function does not have a return type of Boolean, but of an Array[Int].
Take a look at the signature of the filter:
def filter(p: A => Boolean): Repr = filterImpl(p, isFlipped = false)
Filter method accepts a Predicate. You may map you internals arrays and then filter by your rules.
I have a following code, which copies an array of Rider objects, and appends a new Rider object if it exists.
let riders:[Rider] = getRiders()
let newRider:Rider? = mayGetNewRider()
var ridersPlus = riders
if let rider = newRider {
ridersPlus.append(rider)
}
I am looking for a better (simpler and easier to read) way to write this logic, which also allows me to define ridersPlus as "let" variable.
I am looking for something like below (which is invalid, because I made up the ??? syntax, which produces an empty array of newRider is nil).
let riders:[Rider] = getRiders()
let newRider:Rider? = mayGetNewRider()
let ridersPlus = riders + [newRider???]
How about
let ridersPlus = riders + [newRider].compactMap {$0}
(Note that before Swift 4, compactMap would be called flatMap. You didn't say what Swift version you are using.)
You do it with map and the nil coalescing operator ??:
let ridersPlus = riders + (newRider.map {[$0]} ?? [])
map when called on an Optional value evaluates the given closure when the Optional instance is not nil, passing the unwrapped value as a parameter. If the Optional is nil, the result of the map is nil. Combining that with the nil coalescing operator, the resulting Optional array can be unwrapped or replaced with [] and then added to the riders array.
I am trying to sort an Array by using fold or foldBack.
I have tried achieving this like this:
let arraySort anArray =
Array.fold (fun acc elem -> if acc >= elem then acc.append elem else elem.append acc) [||] anArray
this ofcourse errors horribly. If this was a list then i would know how to achieve this through a recursive function but it is not.
So if anyone could enlighten me on how a workable function given to the fold or foldback could look like then i would be createful.
Before you start advising using Array.sort anArray then this wont do since this is a School assignment and therefore not allowed.
To answer the question
We can use Array.fold for a simple insertion sort-like algorithm:
let sort array =
let insert array x =
let lesser, greater = Array.partition (fun y -> y < x) array
[| yield! lesser; yield x; yield! greater |]
Array.fold insert [||] array
I think this was closest to what you were attempting.
A little exposition
Your comment that you have to return a sorted version of the same array are a little confusing here - F# is immutable by default, so Array.fold used in this manner will actually create a new array, leaving the original untouched. This is much the same as if you'd converted it to a list, sorted it, then converted back. In F# the array type is immutable, but the elements of an array are all mutable. That means you can do a true in-place sort (for example by the library function Array.sortInPlace), but we don't often do that in F#, in favour of the default Array.sort, which returns a new array.
You have a couple of problems with your attempt, which is why you're getting a few errors.
First, the operation to append an array is very different to what you attempted. We could use the yield syntax to append to an array by [| yield! array ; yield element |], where we use yield! if it is an array (or in fact, any IEnumerable), and yield if it is a single element.
Second, you can't compare an array type to an element of the array. That's a type error, because compare needs two arguments of the same type, and you're trying to give it a 'T and a 'T array. They can't be the same type, or it'd be infinite ('T = 'T array so 'T array = 'T array array and so on). You need to work out what you should be comparing instead.
Third, even if you could compare the array to an element, you have a logic problem. Your element either goes right at the end, or right at the beginning. What if it is greater than the first element, but less than the last element?
As a final point, you can still use recursion and pattern matching on arrays, it's just not quite as neat as it is on lists because you can't do the classic | head :: tail -> trick. Here's a basic (not-so-)quicksort implementation in that vein.
let rec qsort = function
| [||] -> [||]
| arr ->
let pivot = Array.head arr
let less, more = Array.partition (fun x -> x < pivot) (Array.tail arr)
[| yield! qsort less ; yield pivot ; yield! qsort more |]
The speed here is probably several orders of magnitude slower than Array.sort because we have to create many many arrays while doing it in this manner, which .NET's Array.Sort() method does not.
According to Scaladoc, there is no method named map in Array class, but there is an implicit function implicit def intArrayOps (xs: Array[Int]): ArrayOps[Int] defined in scala.Predef. So you can apply map on Array(1,2,3,4) if you like. But What I am confused about is that the map result is of type Array[Int], not ArrayOps[Int]. Here is my test:
scala> val array = Array(1,2,3,4)
array: Array[Int] = Array(1, 2, 3, 4)
scala> array.map(x => x)
res18: Array[Int] = Array(1, 2, 3, 4)
scala> res18.isInstanceOf[Array[Int]]
res19: Boolean = true
scala> res18.isInstanceOf[scala.collection.mutable.ArrayOps[Int]]
warning: there wre 1 unchecked warnings; re-run with -unchecked for details
res20: Boolean = false
It indeed returns an array, as intended and as is convenient, there is no reason you would need an ArrayOps, it is intended only to provide extra methods to arrays. The doc is wrong.
The routine is actually not implemented in ArrayOps. As most collection methods, it is inherited from TraversableLike. And you see two map methods in the doc:
def map [B] (f: (T) ⇒ B): ArrayOps[B]
def map [B, That] (f: (T) ⇒ B)(implicit bf: CanBuildFrom[Array[T], B, That]): That
Only the second one exists (inherited from TraversableLike). It is intended to allow implementation of map in just one place (traversable like) while allways giving the best possible behavior. For instance, a String is a of Seq[Char], if you map with a function from character to character, you get a String, but if you map from collection to say Int, the result cannot be a String and it will just be a Seq. This is explained in much detail in the paper fighting the bit rot with types.
However, this makes for a very complex signature, which does not reflect the simplicity of using the method, and makes very poor documentation most of the time (you normally would have to chase to which CanBuildFrom in implicit scope would work). This was discussed in this most famous scala question of stack overflow. So the tool scaladoc was extended so that a simpler entry, corresponding to intended usage, may appear. If you look at the source of GenTraversableLike, where the routine is introduced, you will see the following in the scaladoc for map (and a similar one in many methods)
#usecase def map[B](f: A => B): $Coll[B]
Subtypes add in their doc #define Coll <className>, and map (among others) appears with the simplified signature, marked [Use case]. In the source of ArrayOps, there is a #define Coll ArrayOps where it should be Array.
You can use the REPL with the -Xprint:typer option to see what's going on. Here is the output of the map method, reformatted for easier reading:
$ scala -Xprint:typer
scala> Array(1,2,3,4).map(x => x)
[[syntax trees at end of typer]]// Scala source: <console>
// some lines deleted
private[this] val res0: Array[Int] =
scala.this.Predef.intArrayOps(scala.Array.apply(1, 2, 3, 4))
.map[Int, Array[Int]]
(( (x: Int) => x ))
(scala.this.Array.canBuildFrom[Int](reflect.this.Manifest.Int));
So simplifying for package names here is what happens:
intArrayOps(Array(1,2,3,4)) // converts to ArrayOps
.map[Int, Array[Int]] // calls map with parameter lists below
((x:Int) => x) // pass identity function as fisrt param
(Array.canBuildFrom[Int]// pass builder for Array[Int] as second param
(Manifest.Int)) // pass class manifest for Int
So there is indeed a conversion to ArrayOps (first line). It returns ArrayOps[Int].
The ArrayOps.map[Int, Array[Int]] method is then called on it. Then as didierd explain, the original signature for map - not the simplified signature - indicates that the return type inferred will be Array[Int]