Scala BigInt Array - arrays

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].

Related

How do i extend a class which needs a ClassTag AND to extend Comparable?

I have a simple class I always implement when working with a new Language, MergeSort. So I am looking at my implementations of it with type Int and it looks great. Then I wanted to genericize it. I started with a simple implementation of T, but i noticed that needed to relfect the ClassTag. How do i assign the reflected ClassTag + extending?
class MergeSort[T: scala.reflect.ClassTag] {
var array: Array[T] = Array[T]()
var length: Int = 0
var tempArray: Array[T] = new Array(length)
def sort(data: Array[T]): Unit = {
array = data;
length = data.length;
tempArray = new Array[T](length)
//sort(0, length - 1)
}
}
Now this looks nice! It works, but when I i do the sort and rest of the functionality, I need to be able to compare 2 items of type T. The "Java" way was to just make sure the Object has the compareTo method. So i was thinking: [T extends Comparable]
but in scala, I am doing assignment for T with ClassTag, and
class MergeSort[T: scala.reflect.ClassTag extends Comparable] {} for example. It will error saying:
']' expected, but 'extends' found.
I was thinking this would sorta be the way to do things, but i am not sure whats going on here.
The endstate is to implement the merge portion of the class:
def merge(lower: Int, center: Int, upper: Int){
// ...
// loop
// if (tempArr(i) <= tempArr(j)) {} // OLD WAY, since First attempt was with Int.
// if (tempArr(i).compareTo(tempArr(j)) < 0) {} // Modified way with Comparable
}
Is this the scala way of implementing? I was noticing that people were mentioning Ordering, but i thought Comparable made sense.
The Scala way of implementing merge sort is using List and vals and the Ordering trait. The advantage of Ordering (the Java Comparator) is that Scala gives you implicit orderings for all standard library types by default.
def msort[T: Ordering](xs: List[T]): List[T] = {
#tailrec
def merge(xs: List[T], ys: List[T], acc: List[T] = Nil): List[T] =
(xs, ys) match {
case (Nil, _) => acc.reverse ++ ys
case (_, Nil) => acc.reverse ++ xs
case (x :: xs1, y :: ys1) =>
if (implicitly[Ordering[T]].lt(x, y))
merge(xs1, ys, x :: acc)
else
merge(xs, ys1, y :: acc)
}
xs match {
case Nil | _ :: Nil => xs
case _ =>
val (xs1, xs2) = xs splitAt (xs.length / 2)
merge(msort(xs1), msort(xs2))
}
}
msort(List(4, 23, 1, 2, 5, 76, 3, 142, 4321, 213, 42323))
// List(1, 2, 3, 4, 5, 23, 76, 142, 213, 4321, 42323)
msort(List("John", "Chris", "Helen", "Danny", "Michelle"))
// List(Chris, Danny, Helen, John, Michelle)
Another advantage over Ordered is that Scala provides implicit conversions from Ordered[A] => Ordering[A], which means your custom types that mix in Ordered will work with msort without the need to define implicit orderings.
Finally, the last advantage over Ordered is when using numeric types: Int, Double, etc. do not mix in Ordered, so you will not be able to sort elements of these types with Ordered, this is why most use Ordering instead.
I'm well aware this variant is not in-memory, but it does not require ClassTag at all to implement.

Applying the filter function on an Array of Arrays returns an exception in Scala

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.

Type Mismatch in scala, Array[Int] and Array[Option[Int]]

First, I am new to Scala, So apologies if the following question is too simple.
I have written the following code to the find the values of the keys that I supply in an array from the map.
def stringToCountMap(inputArray: Array[String], inputMap:Map[String,Int]) : Array[Int] = {
return inputArray.map(x => inputMap.get(x))
}
I got the following error,
type mismatch;
found : Array[Option[Int]]
required: Array[Int]
return inputArray.map(x => inputMap.get(x))
Question:
1) Can anyone explain what is Option[Int]?
2) What is my mistake here ?
Thanks in advance.
Option is Scala's option type (also called a nullable type). It represents a case where the value may not exist.
Consider a map that doesn't contain a requested key. How would you handle a request for the key? One option is to result in an error, such as by throwing an exception. Another is to return a special value that indicates there is no value. Map.get does the latter, using Option as the special type and None as the value. This means the return type of Map.get isn't the value type of the map (Int), but Option applied to the value type (Option[Int]).
To correct the type declaration, change the return type:
def stringToCountMap(inputArray: Array[String], inputMap:Map[String,Int]) : Array[Option[Int]] = {
inputArray.map(x => inputMap.get(x))
}
You can leave out the return type of stringToCountMap and let type inference handle it:
def stringToCountMap(inputArray: Array[String], inputMap:Map[String,Int]) = {
inputArray.map(x => inputMap.get(x))
}
As a consequence, missing keys from the input map get carried through:
scala> stringToCountMap(Array("a", "def"), Map("a" -> 1, "bc" -> 2))
res0: Array[Option[Int]] = Array(Some(1), None)
Option[T] is a wrapper around a value of type T. Its purpose is to prevent NullPointerException, that you might know from Java. A value of type Option[T] might either be None, which, as the name implies is an object that represents nothing, or it might be Some(x: T), which represents an existing value.
inputMap(x) returns an Option[Int], since you have no guarantee that the x key exists in inputMap. If it does, it returns Some(value: Int), else it returns None.
Calling stringToCountMap(Array("a", "b", "c"), Map("a" -> 1, "c" -> 2)) results in Array(Some(1), None, Some(2))
If you want an Array[Int] instead, you might do something like inputArray.map(x => inputMap.getOrElse(x, 0)).get. The getOrElse method has two parameters, where the first one is the key, and the second one is the default value. inputArray.map(x => inputMap.get(x).getOrElse(0)) has the same effect, since calling getOrElse(value) on an Option either unwraps the Some object, or returns the default value.
Now, stringToCountMap(Array("a", "b", "c"), Map("a" -> 1, "c" -> 2)) results in Array(1, 0, 2).
You might also want to omit the keys missing in the input array. In that case, you might do inputArray.flatMap(x => inputMap.get(x)). flatMap is a function similar to map, but it returns strictly, as the name implies, flat collections. For example, calling flatMap(x => x) on an Array[Array[Int]] would return an Array of all the values in the 2D array in a single row.
Here, Option is a collection, as well. If it is of type Some, it contains a single value, if it is None, it is an empty collection. Thus, in the resulting array you would only have the values of the keys present in the map, and the keys not present in the map are skipped.
Now, stringToCountMap(Array("a", "b", "c"), Map("a" -> 1, "c" -> 2)) results in Array(1, 2).
First, there is no need to use 'return' in scala to return any value.
def stringToCountMap(inputArray: Array[String], inputMap:Map[String,Int]) = {
inputArray.map(x => inputMap.get(x))
}
When you get the value of key from Map, It returns result in Option.
For example:
scala> val map = Map(1-> "a",2 -> "b")
map: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b)
scala> map.get(1)
res0: Option[String] = Some(a)
scala> map.get(3)
res1: Option[String] = None
When you try to get the value of key, which does not exist. In java, you have encountered with NullPointerException. So when there is no value, it returns None to avoid exception.
For more info refer
In your method, you have given return type as Array[Int] but function returns Array[Option[Int]] that's why it throws compilation error.

Understanding syntax for an array of tuples in Swift

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")]

Scala Array Slicing with Tuple

I try to slice an 1D Array[Double] using the slice method. I've written a method which returns the start and end index as a tuple (Int,Int).
def getSliceRange(): (Int,Int) = {
val start = ...
val end = ...
return (start,end)
}
How can I use the return value of getSliceRange directly?
I tried:
myArray.slice.tupled(getSliceRange())
But this gives my a compile-Error:
Error:(162, 13) missing arguments for method slice in trait IndexedSeqOptimized;
follow this method with `_' if you want to treat it as a partially applied function
myArray.slice.tupled(getSliceRange())
I think the problem is the implicit conversion from Array to ArrayOps (which gets slice from GenTraversableLike).
val doubleArray = Array(1d, 2, 3, 4)
(doubleArray.slice(_, _)).tupled
Function.tupled[Int, Int, Array[Double]](doubleArray.slice)
(doubleArray.slice: (Int, Int) => Array[Double]).tupled
Two options here, the first one is to call your function twice:
myArray.slice(getSliceRange()._1, getSliceRange()._2)
or to save your Tuple beforehand:
val myTuple: (Int, Int) = getSliceRange()
myArray.slice(myTuple._1, myTuple._2)
Edit: I leave this here just in case but Peter Neyens posted the expected answer.

Resources