I am trying to process a tuple, where one of the cases is that the two values are equal. Is there a better, more concise way to match on this than
(p, q) match {
case (p, q) if (p == q) => println("Match!")
...
}
?
Personally, I think the way you've done it is great because it's simple, intuitive, and clear to the reader what's going on.
That said, here's one way you could do it without an if clause. You could just match on the swapped version, using backticks to turn q into stable identifiers. As #Luigi pointed out, you can just check that p matches q:
(p, q) match {
case (`q`, _) => println("Match!")
...
}
Like this:
def f(p: Int, q: Int) {
(p, q) match {
case (`q`, _) => println("Match!")
case _ => println("No")
}
}
f(1, 2) // "No"
f(1, 1) // "Match!"
You can define your own extractor:
object Eq {
def unapply[T](pair:(T,T)):Option[T] =
if (pair._1 == pair._2) Some(pair._1) else None
}
Then (4,4) match { case Eq(n) => println("same: " + n) } prints same: 4, while (3,4) wouldn't match.
I listed some comparision extractors in my blog (sorry, it's in German).
You can swap the values and then compare the tuple with its normal equals-method:
scala> val t = (1, 1)
t: (Int, Int) = (1,1)
scala> t.swap == t
res0: Boolean = true
scala> val t = (1, 2)
t: (Int, Int) = (1,2)
scala> t.swap == t
res1: Boolean = false
Related
I have an exercise to check if two adjoined elements are ordered using sliding,map,reduceLeft. For example:
val seq1 = Seq(1,2,2,4)
isOrdered(seq1)(_ < _) == false
isOrdered(seq1)(_ <= _) == true
def isOrdered[A](seq: Seq[A])(leq: (A,A) => Boolean): Boolean = {
}
honestly I don't know what to start with.
"using sliding,map,reduce"
def isOrdered[A](seq: Seq[A])(pred: (A,A) => Boolean): Boolean =
seq.sliding(2)
.map{case Seq(a,b) => pred(a,b)}
.reduce(_ && _)
Note: Not safe for sequences smaller than 2 elements.
Here's how you can do it using those three operations:
def isOrdered[A](seq: Seq[A])(leq: (A, A) => Boolean): Boolean =
seq
.sliding(2)
.map { case e1 :: e2 :: Nil => leq(e1, e2) }
.reduceLeft(_ && _)
First we divide the sequence into groups of two consecutive elements using sliding. Then we apply leq on each pair (in other words, we map each two-element list into result of leq on those two elements). Lastly, we reduce the result sequence of Booleans into a single Boolean with a logical AND, meaning that our predicate needs to hold for all values.
val seq1 = Seq(1, 2, 2, 4)
val less: (Int, Int) => Boolean = _ < _
val lessOrEqual: (Int, Int) => Boolean = _ <= _
isOrdered(seq1)(less) // false
isOrdered(seq1)(lessOrEqual) // true
There are some unsafety concerns here:
If you have a one-element sequence, the sliding operation will produce an iterator over a single-list element, and the pattern matching will fail.
If you have an empty sequence, reduce will explode.
One approach includes forall, where leq: (A,A) => Boolean must hold for each and every element,
def isOrdered[A](seq: Seq[A])(leq: (A,A) => Boolean): Boolean = {
seq.sliding(2).forall { case(Seq(l,r)) => leq(l,r) }
}
Thus for val seq1 = Seq(1,2,2,4),
scala> isOrdered(seq1)(_<_)
val res5: Boolean = false
scala> isOrdered(seq1)(_<=_)
val res6: Boolean = true
Let us have a collection of collections as below:
type Row = IndexedSeq[Any]
type RowTable = IndexedSeq[Row]
val table: RowTable = IndexedSeq(
IndexedSeq(2, "b", ... /* some elements of type Any*/),
IndexedSeq(1, "a", ...),
IndexedSeq(2, "c", ...))
Each Row in RowTable "has the same schema", meaning that as in example if the first row in the table contains Int, String, ..., then the second row in the table contains the elements of the same type in the same order, i.e., Int, String, ....
I would like to sort Rows in a RowTable by given indices of Row's elements and the sorting direction (ascending or descending sort) for that element.
For example, the collection above would be sorted this way for Index 0 ascending and Index 1 descending and the rest of elements are not important in sorting:
1, "a", ...
2, "c", ...
2, "b", ...
Since Row is IndexedSeq[Any], we do not know the type of each element to compare it; however, we know that it may be casted to Comparable[Any] and, thus, has compareTo() method to compare it with an element under the same index in another row.
The indices, as mentioned above, that will determine the sorting order are not known before we start sorting. How can I code this in Scala?
First of all, it's a bad design to compare a pair of Any.
By default, scala doesn't provide any way to get Ordering[Any]. Hence if you want to compare a pair of Any, you should implement Ordering[Any] by yourself:
object AnyOrdering extends Ordering[Any] {
override def compare(xRaw: Any, yRaw: Any): Int = {
(xRaw, yRaw) match {
case (x: Int, y: Int) => Ordering.Int.compare(x, y)
case (_: Int, _) => 1
case (_, _: Int) => -1
...
case (x: String, y: String) => Ordering.String.compare(x, y)
case (_: String, _) => 1
case (_, _: String) => -1
...
case (_, _) => 0
}
}
}
In your example, you want to compare two IndexedSeq[T] recursively. Scala doesn't provide any recursive Ordering and you need to implement it too:
def recOrdering[T](implicit ordering: Ordering[T]): Ordering[IndexedSeq[T]] = new Ordering[IndexedSeq[T]] {
override def compare(x: IndexedSeq[T], y: IndexedSeq[T]): Int = compareRec(x, y)
#tailrec
private def compareRec(x: IndexedSeq[T], y: IndexedSeq[T]): Int = {
(x.headOption, y.headOption) match {
case (Some(xHead), Some(yHead)) =>
val compare = ordering.compare(xHead, yHead)
if (compare == 0) {
compareRec(x.tail, y.tail)
} else {
compare
}
case (Some(_), None) => 1
case (None, Some(_)) => -1
}
}
}
After that you can finally sort your collection:
table.sorted(recOrdering(AnyOrdering))
(Sorry for unidiomatic (maybe not compiling) code; I can probably help with it upon request)
We can use the code below to sort a table
table.sortWith {
case (tupleL, tupleR) => isLessThan(tupleL, tupleR)
}
where isLessThan is defined as follows (unidiomatic to Scala, ik):
def isLessThan(tupleL: Row, tupleR: Row): Boolean = {
var i = 0
while (i < sortInfos.length) {
val sortInfo = sortInfos(i)
val result = tupleL(sortInfo.fieldIndex)
.asInstanceOf[Comparable[Any]].compareTo(
tupleR(sortInfo.fieldIndex)
.asInstanceOf[Comparable[Any]])
if (result != 0) {
if (sortInfo.isDescending) {
if (result > 0)
return true
else
return false
} else {
if (result < 0)
return true
else
return false
}
}
i += 1
}
true
}
where sortInfos is IndexedSeq[SortInfo] and
case class SortInfo(val fieldIndex: Int, val isDescending: Boolean)
Here is working Example with Ordering[IndexedSeq[Any]]:
val table: IndexedSeq[IndexedSeq[Any]] = IndexedSeq(
IndexedSeq(2, "b", "a"),
IndexedSeq(2, "b"),
IndexedSeq("c", 2),
IndexedSeq(1, "c"),
IndexedSeq("c", "c"),
//IndexedSeq((), "c"), //it will blow in runtime
IndexedSeq(2, "a"),
)
implicit val isaOrdering:Ordering[IndexedSeq[Any]] = { (a, b) =>
a.zip(b).filter {case (a, b)=> a != b}.collectFirst {
case (a:Int, b:Int) => a compare b
case (a:String, b:String) => a compare b
case (a:String, b:Int) => 1 //prefere ints over strings
case (a:Int, b:String) => -1 //prefere ints over strings
case _ => throw new RuntimeException(s"cannot compare $a to $b")
}.getOrElse(a.length compare b.length) //shorter will be first
}
println(table.sorted) //used implicitly
println(table.sorted(isaOrdering))
//Vector(Vector(1, c), Vector(2, a), Vector(2, b), Vector(2, b, a), Vector(c, 2), Vector(c, c))
https://scalafiddle.io/sf/yvLEnYL/4
or if you really need to compare different types somehow this is best I could find:
implicit val isaOrdering:Ordering[IndexedSeq[Any]] = { (a, b) =>
a.zip(b).filter {case (a, b)=> a != b}.collectFirst {
case (a:Int, b:Int) => a compare b
case (a:String, b:String) => a compare b
//add your known types here
// ...
//below is rule that cares about unknown cases.
//We don't know types at all, at best what we can do is compare equality.
//If they are equal then return 0... if not we throw
//this could be also very slow (don't tested)
case (a, b) =>
//not nice but it is stable at least
val ac = a.getClass.getName
val bc = b.getClass.getName
ac.compare(bc) match {
case 0 => if (ac == bc) 0 else throw new RuntimeException(s"cannot compare $a to $b")
case x => x
}
}.getOrElse(a.length compare b.length) //shorter will be first
}
https://scalafiddle.io/sf/yvLEnYL/5
This implementation will fail in runtime when we could not compare them.
I have a requirement where I have to search a character in vector of vectors. I have written a method which is very crude. What is a better way to search an element in vector of vectors.
Here is my code:
def search( xs: Vector[Vector[Char]], char: Char, rowIndex: Int): Pos = xs.headOption match {
case None => Pos(-1, -1)
case Some(row) => {
val tuple = searchHelper(row, char, 0)
if(tuple._1)
Pos(rowIndex, tuple._2)
else
search(xs.tail, char, rowIndex +1)
}
}
def searchHelper(xs: Vector[Char], char: Char, colIndex: Int): (Boolean, Int) = xs.headOption match {
case None => (false, colIndex)
case Some(col) =>
if(col == char)
(true, colIndex)
else
searchHelper(xs.tail, char, colIndex +1)
}
search(vector, c, 0)
Here is the input:
val input =
"""ooo-------
|oSoooo----
|ooooooooo-
|-ooooooooo
|-----ooToo
|------ooo-""".stripMargin
val vector =
Vector(input.split("\n").map(str => Vector(str: _*)): _*)
val c = 'S'
Something like this, perhaps?
xs
.iterator
.zipWithIndex
.map { case (chars, idx) => (idx, chars.indexOf(c)) }
.collectFirst {
case (outer, inner) if(inner >= 0) => Pos(outer, inner)
}.getOrElse(Pos(-1, 1))
To address a concern from the comments: this is not iterating through the entire list multiple times (not even once completely, as long as it finds a match earlier). Scala iterators are wonderful that way: you can write a chain of calls, that conceptually looks like a bunch of sequential transformations to the entire list, but is really executed lazily, element by element: the first element is is extracted from list, converted to a tuple (chars, 0), fed to the map, then the result of that is sent to collectFirst, if the condition matches there, it stops and returns right away, otherwise, next element is taken from list, made into a tuple (chars, 1), fed to the .map, etc ...
If, with better, you mean more concise, you could try leveraging the methods on Scalas collections:
def search( xs: Vector[Vector[Char]], c: Char ): (Int, Int) = {
var innerIndex = -1
val outerIndex = xs.indexWhere { inner =>
innerIndex = inner.indexOf(c)
innerIndex > -1
}
(outerIndex, innerIndex)
}
This assumes that you only need the first occurence of that character.
indexWhere terminates as soon as the innerIndex is larger than -1.
Maybe another possibility, which goes more in your recursive direction (and without a mutable var), but also with minimal iterations:
#tailrec
def search(xs: Vector[Vector[Char]], c: Char, n: Int = 0): (Int, Int) = {
if (n > xs.size - 1) (-1, -1)
else
xs(n).indexOf(c) match {
case -1 => search(xs, c, n + 1)
case i => (n, i)
}
}
Simplest way of doing it :
def findChar(c: Char, levelVector: Vector[Vector[Char]]): Pos =
val x = levelVector.indexWhere(_.contains(c))
val y = levelVector(x).indexWhere(_ == c)
Pos(x,y)
Indeed you have to assume there is only one correct answer.
Main idea :
First search for the row that have the character c
Then find the column in this row that has this character c
I am starting the Scala programming course on Coursera, coming from 2 years experience with Java/Python/C#.
I am working through a problem where you must check to see if a list of characters has balanced paranthesis.
/**
* Exercise 2
*/
def balance(chars: List[Char]): Boolean = {
def recursiveBalance(chars: List[Char]): Boolean = {
if (!chars.contains('(') && !chars.contains(')')) true
else {
val openIndex = chars.indexOf('(')
if (openIndex == -1) false
else {
val chars2 = dropFirstMatch(chars, '(')
val closeIndex = chars2.indexOf(')')
if(closeIndex == -1 || openIndex > closeIndex) false
else recursiveBalance(dropFirstMatch(chars2, ')'))
}
}
}
def remove(index: Int, list: List[Char]): List[Char] = {
list.take(index) ++ list.drop(index)
}
def dropFirstMatch[A](ls: List[A], value: A): List[A] = {
val index = ls.indexOf(value) //index is -1 if there is no match
if (index < 0) {
ls
} else if (index == 0) {
ls.tail
} else {
// splitAt keeps the matching element in the second group
val (a, b) = ls.splitAt(index)
a ++ b.tail
}
}
recursiveBalance(chars)
}
So this solution is working (if a little ugly). As part of the solution I attempted to remove an object from a list at a specific index. I've learned that in Scala Lists are immutable.
My attempt at doing this was to provide the index, the list, and use this example, which is the remove function. This works in the REPL, I made a list, ran the function and a new list was returned without the specified index.
But this did not work in my balance solution. Everytime the list was returned it was unchanged, causing infinite recursion. Eventually I stumbled on this article and borrowed their dropFirstMatch function, and upon substituting it, bam, working solution.
I am very new to Scala, and I must be overlooking something - can someone point out what it might be?
take(n) selects the first n elements in your list, where drop(n) selects all elements of the list except the first n ones.
To illustrate:
scala> val xs = List(0,1,2,3,4,5)
xs: List[Int] = List(0, 1, 2, 3, 4, 5)
scala> xs.take(2)
res0: List[Int] = List(0, 1)
scala> xs.drop(2)
res1: List[Int] = List(2, 3, 4, 5)
scala> xs.take(2) ++ xs.drop(2)
res2: List[Int] = List(0, 1, 2, 3, 4, 5)
In other words, your remove function simply returns the same list because it takes the first n elements of the original list, then adds that to the elements of the original list except the first n ones (drop). In order to remove the element at the given index in your list, you merely need to increment the index by one in your call to drop:
def remove(index: Int, list: List[Char]): List[Char] = {
list.take(index) ++ list.drop(index+1)
}
Checking for balanced parenthesis is way easier than what you are doing:
def balanced(list: Seq[Char]): Boolean = list.foldLeft(0) {
case (n, _) if (n < 0) => return false
case (n, '(') => n + 1
case (n, ')') => n - 1
case (n, _) => n
} == 0
Or, if you are a purist, like some commenters, and insist on recursion:
#tailrec
def balanced(chars: Seq[Char], n: Int = 0): Boolean = (n, chars) match {
case (-1, _) => false
case (n, Nil) => n == 0
case ('(' :: tail, n) => balanced(tail, n+1)
case (')' :: tail, n) => balanced(tail, n-1)
case (_ :: tail, n) => balanced(tail, n)
}
I'm looking to match a sequence within a sequence like either in ex 1 or ex 2;
List(1, 2, 3, 4) match {
case 1 :: List(_*) :: 4 :: tail => // Ex 1
case 1 :: (seq : List[Int]) :: 4 :: tail => // Ex 2
case _ =>
}
This is a variant to the fixed length sequence pattern _*. Like the _*, I don't care about the content of the inner pattern, but it is important that the length can vary and that the pattern is surrounded by a prefix (such as the 1 above) and a suffix (like the 4).
My question is if any of you have a trick to do this by some crafty unapply magic or if you'd just iterate the list to search for the sequence manually.
Thanks in advance! :-)
This is really outside the scope of what pattern matching is supposed to be used for. Even if you could finagle a set of custom unapply methods to do what you wanted, it wouldn't be apparent whether matching was greedy or not, etc..
However, if you really want to, you can proceed as follows (for example):
import scala.collection.SeqLike
class Decon[A](a0: A, a1: A) {
def unapply[C <: SeqLike[A, C]](xs: C with SeqLike[A, C]): Option[(C, C)] = {
xs.span(_ != a1) match {
case (a0 +: pre, a1 +: post) => Some((pre,post))
case _ => None
}
}
}
val Dc = new Decon(1,4)
scala> List(1,2,3,4,5) match { case Dc(pre, post) => (pre, post); case _ => (Nil, Nil) }
res1: (List[Int], List[Int]) = (List(2, 3),List(5))
Separating the specification of the fixed elements 1 and 4 from the match is necessary; otherwise the normal algorithm would ask the unapply to return values without any knowledge of what was being sought, and then would test to make sure they were correct.
You could do something like this:
List(1,2,3,4) match {
case 1 :: tail if tail.last == 4 => println("Found it!")
}
But if you check the implementation of last in LinearSeqOptimized:
def last: A = {
if (isEmpty) throw new NoSuchElementException
var these = this
var nx = these.tail
while (!nx.isEmpty) {
these = nx
nx = nx.tail
}
these.head
}
It is iterating indeed. This is because List inherits from LinearSeq which are optimized to provide efficient head and tail operations. For what you want to do, it is better to use an IndexedSeq implementation like Vector which has an optimized length operation, used in last:
override /*TraversableLike*/ def last: A = {
if (isEmpty) throw new UnsupportedOperationException("empty.last")
apply(length-1)
}
So you could do something like this:
Vector(1,2,3,4) match {
case v if v.head == 1 && v.last == 4 => println("Found it!")
}