How do I compare two arrays in scala? - arrays

val a: Array[Int] = Array(1,2,4,5)
val b: Array[Int] = Array(1,2,4,5)
a==b // false
Is there a pattern-matching way to see if two arrays (or sequences) are equivalent?

From Programming Scala:
Array(1,2,4,5).sameElements(Array(1,2,4,5))

You need to change your last line to
a.deep == b.deep
to do a deep comparison of the arrays.

a.corresponds(b){_ == _}
Scaladoc: true if both sequences have
the same length and p(x, y) is true
for all corresponding elements x of
this wrapped array and y of that,
otherwise false

For best performance you should use:
java.util.Arrays.equals(a, b)
This is very fast and does not require extra object allocation. Array[T] in scala is the same as Object[] in java. Same story for primitive values like Int which is java int.

As of Scala 2.13, the deep equality approach doesn't work and errors out:
val a: Array[Int] = Array(1,2,4,5)
val b: Array[Int] = Array(1,2,4,5)
a.deep == b.deep // error: value deep is not a member of Array[Int]
sameElements still works in Scala 2.13:
a sameElements b // true

It didn't look like most of the provided examples work with multidimensional arrays. For example
val expected = Array(Array(3,-1,0,1),Array(2,2,1,-1),Array(1,-1,2,-1),Array(0,-1,3,4))
val other = Array(Array(3,-1,0,1),Array(2,2,1,-1),Array(1,-1,2,-1),Array(0,-1,3,4))
assert(other.sameElements(expected))
returns false, throws an assertion failure
deep doesn't seem to be a function defined on Array.
For convenience I imported scalatest matchers and it worked.
import org.scalatest.matchers.should.Matchers._
other should equal(expected)

Related

Converting Array[(Double,Double)] to Seq[Seq[Double]]

I am fairly new to Scala and I have to use a function which takes as argument of type Seq[Seq[Double]]. However, my data has the type Array[(Double,Double)].
I tried using .toSeq to convert the data, but that doesn't work.
Any fixes in this regard would be highly appreciated. Thanks!
val input: Array[(Double, Double)] = ...
val output: Seq[Seq[Double]] = input.map { case (x, y) => Seq(x, y) }
Unfortunately, there is no generic way to type-safely convert a tuple to a list in the standard library. shapeless, however, does provide this functionality:
import shapeless.syntax.std.tuple._
val input: Array[(Double, Double)] = ...
val output: Seq[Seq[Double]] = input.map(_.toList)
Shapeless is smart enough to compute a lowest upper bound in case your tuple contains components of different types:
val input: Array[(Double, Int)] = ...
// AnyVal is the closest type which both Double and Int are subtypes of
val output: Seq[Seq[AnyVal]] = input.map(_.toList)
Finally, there is a non-type-safe way to do this using only the standard library tools. You can rely on the fact that all tuples in Scala implement the Product trait and therefore are iterable as collections of Any:
val input: Array[(Double, Double)] = ...
val output: Seq[Seq[Double]] = input.map(_.productIterator.toSeq.asInstanceOf[Seq[Double]])
This is safe as long as you're careful, but it does require an explicit cast and it is more verbose.
If you have fixed-length tuples of relatively small size, then I'd say it is better to use the partial function-based approach. Otherwise, it is up to you, but I'd use shapeless because it is type safe, and I also use shapeless in many of my projects for other things as well, so it is kind of free for me :)

How to get a correct array hashcode in scala?

What is the suitable way to compute hashCode of an Array that depends on its content?
Array.hashCode is for the array instance:
val h = a.hashCode
println(h == Array(1,2).hashCode) // false
a(0) = 42
println(h == a.hashCode) // true
Note: It'd be better to avoid copying the whole array, to a List for example, prior to computing the hashCode
Why I ask: I use an Array in a class (as a private field) because lookup time is critical, and its content is relevant to compute the hashCode of the class
from https://issues.scala-lang.org/browse/SI-1607, it says that the hashCode of Array is the hashCode from java, as scala Array are java Array. And scala could not changed it.
But it also says that scala has a suitable hashCode method in WrappedArray.
Thus:
val a = Array(1,2)
val h = a.toSeq.hashCode // wrapped it in a WrappedArray - no copy
println(h == Array(1,2).toSeq.hashCode) // true
a(0) = 42
println(h == a.toSeq.hashCode) // false
You can also use java.util.Arrays.hashCode(a), it's likely to be faster than a.toSeq.hashCode (since WrappedArray seems to inherit a non-array-specific implementation).
You can use the MurmurHash3 algorithm directly.
import scala.util.hashing.MurmurHash3
MurmurHash3.orderedHash(Array(1,2)))

Obtaining array element in Scala works only with explicit apply method

Accessing collection elements in Scala is done by apply method. Having said that I tried to read numbers from standard input and get the second one as int in just one line.
def main(args: Array[String]): Unit = {
val number = StdIn.readLine().split(" ").map(_.toInt)(1)
}
IntelliJ marks this 1 and show the error (the same is shown after the compilation attempt):
Error:(11, 60) type mismatch; found : Int(1) required:
scala.collection.generic.CanBuildFrom[Array[String],Int,?]
val number = StdIn.readLine().split(" ").map(_.toInt)(1)
Folding the expression in the parentheses dosn't help as well. However, when I split mapping input to int array and getting the element to other lines, everything works fine.
def main(args: Array[String]): Unit = {
val numbers = StdIn.readLine().split(" ").map(_.toInt)
numbers(1)
}
The explicit invocation of apply also does the job:
val number = StdIn.readLine().split(" ").map(_.toInt).apply(1)
Why does this weird behaviour happens? Obtaining element via array(5) is just a shortcut for array.apply(5), isn't it?
As compiler already pointed out, map is defined with two arg lists. second one containing a single implicit param: implicit bf: CanBuildFrom[Repr, B, That]
For a vast majority of scenarios, the users don't worry about specifying the second arg. Specifically, in your case this is what the compiler "figures out":
StdIn.readLine().split(" ").map(_.toInt)(Array.canBuildFrom[Int])
So, if writing out apply is not desired then the following is the only choice:
StdIn.readLine().split(" ").map(_.toInt)(Array.canBuildFrom[Int])(1)
It's a bit counter-intuitive that adding a set of parentheses still doesn't quite do the trick:
( StdIn.readLine().split(" ").map(_.toInt) )(1) //does not compile, same error
Perhaps it's best to demonstrate what's going with a simpler example. Consider the following function:
def add(x:Int)(y:Int) = x + y
The type of add(2) is Int => Int (since we haven't specified y). Note that adding a set of parentheses around it doesn't change the return type, i.e. (add(2)) still has a type Int => Int. Similarly, (Array("1").map(_.toInt))(1) still requires an instance of CanBuildFrom before using shorthand for apply.
Suggested reading about Scala collections:
The Architecture of Scala Collections
Getting to know CanBuildFrom (without a PhD)
and implicit scope:
Scala Specification <- as comprehensive as it gets
Where does Scala look for implicits?
You're getting a collision with an implicit argument to map. This is one of the cases apply needs to be invoked explicitly.
Here's some REPL that replicates the error:
scala> class Foo {
def apply() { println("bar") }
}
scala> def makeFoo(): Foo = new Foo
scala> makeFoo()()
bar // got the println from the apply here
scala> def makeFooImplicit()(implicit x: Int): Foo = new Foo
scala> implicit val x = 5
scala> makeFooImplicit()()
<console>:11: error: not enough arguments for method makeFooImplicit:(implicit x: Int)Foo.
Unspecified value parameter x.
makeFooImplicit()()

How to compare two arrays in Kotlin?

Given some arrays in Kotlin
let a = arrayOf("first", "second")
val b = arrayOf("first", "second")
val c = arrayOf("1st", "2nd")
Are there built-in functions to the Kotlin std-lib that tests two arrays for (value) equality for each element?
Thus resulting in:
a.equals(b) // true
a.equals(c) // false
equals() is actually returning false in both cases, but maybe there are built-in functions to Kotlin that one could use?
There is the static function java.utils.Arrays.deepEquals(a.toTypedArray(), b.toTypedArray()) but I would rather prefer an instance method as it would work better with optionals.
In Kotlin 1.1 you can use contentEquals and contentDeepEquals to compare two arrays for structural equality. e.g.:
a contentEquals b // true
b contentEquals c // false
In Kotlin 1.0 there are no "built-in functions to the Kotlin std-lib that tests two arrays for (value) equality for each element."
"Arrays are always compared using equals(), as all other objects" (Feedback Request: Limitations on Data Classes | Kotlin Blog).
So a.equals(b) will only return true if a and b reference the same array.
You can, however, create your own "optionals"-friendly methods using extension functions. e.g.:
fun Array<*>.equalsArray(other: Array<*>) = Arrays.equals(this, other)
fun Array<*>.deepEqualsArray(other: Array<*>) = Arrays.deepEquals(this, other)
P.S. The comments on Feedback Request: Limitations on Data Classes | Kotlin Blog are worth a read as well, specifically comment 39364.
Kotlin 1.1 introduced extensions for comparing arrays by content:
contentEquals and contentDeepEquals.
These extensions are infix, so you can use them the following way:
val areEqual = arr1 contentEquals arr2
And if you want to compare contents of two Collections ignoring the order you can add this simple extension:
infix fun <T> Collection<T>.sameContentWith(collection: Collection<T>?)
= collection?.let { this.size == it.size && this.containsAll(it) }
...and use it like this:
a = mutableListOf<String>()
b = mutableListOf<String>()
isListsHasSameContent = a sameContentWith b
For a simple equals (not deep equals!):
otherArray.size == array.size && otherArray.filter { !array.contains(it) }.isEmpty()
This code will compare the size and the items. The items are compared with .equals().
In koltin if your array or ArrayList is type of a data Class you can simply compare array :a and array :b
like this
if(a == b)
it will return simple boolean if it matched all the value of both arrays, but if you are matching other-than data data Class then you can use this extension to compare it with single value
fun <T> Array<T>.isEqual(comparable: Array<T>): Boolean {
var isChanged = true
if (this.size == comparable.size) {
for (index in 0 until comparable.size) {
if (this[index] != comparable[index]) {
isChanged = false
break
}
}
} else {
isChanged = false
}
return isChanged
}
then you can use your array
val a = arrayOf("first", "second")
val b = arrayOf("first", "second")
println(a.isEqual(b)) //true
a[0] = "third"
println(a.isEqual(b)) //false

Why Array's :+ does not work inside for comprehension?

val tagsArray = tags.split(",")
var trimmedTagsArray: Array[String] = Array()
for(tag <- tagsArray) {
trimmedTagsArray :+ tag.trim
}
trimmedTagsArray is empty afterwards, even though tagsArray contains elements, and even if I omit the trim call.
What am I missing here?
You need to understand the :+ operator. Rather than modifying the existing trimmedTagsArray variable, the :+ is actually returning a new array with the result of the expression "tag.trim" appended to the end. Since you neither yield this result back, or assign it anywhere, this value is discarded.
I believe what you are actually looking for is to replace the line in your for comprehension with the following.
trimmedTagArray = trimmedTagArray :+ tag.trim
While this will accomplish what you want, however, it is not the best solution by far. Instead, try the following...
val trimmedTagsArray = for(tag <- tagsArray) yield {
tag.trim
}
The above will create a val (preferred in Scala over var) that has the desired values while avoiding mutable state.
It works. Just that for(...) {} returns Unit. You want :
for(tag <- tagsArray) yield {
trimmedTagsArray :+ tag.trim
}

Resources