I am trying to solve the following problem from Scala for the impatient. The question is as follows:
Using pattern matching, write a function swap that swaps the first two elements of an array provided its length is at least two.
My solution is:
def swap(sArr:Array[Int]) = sArr.splitAt(2) match {
case (Array(x,y),Array(z)) => Array(y,x,z)
case (Array(x,y),Array()) => Array(y,x)
case _ => sArr
}
My problem is with the first case statement. I think it would pattern-match something like (Array(1,2),Array(3)) whereas I intend it to pattern-match (Array(1,2),Array(3,4,5.....))
Can somebody point out how that would be possible.
Thanks
The problem with your code is that Array(z) means "match a one-element array". What you want is for z to be the whole array, no matter how many elements:
def swap(sArr: Array[Int]) =
sArr.splitAt(2) match {
case (Array(x, y), z) => Array(y, x) ++ z
case _ => sArr
}
However, I would write it with the sequence-matching syntax _* so that you don't have to manually split the array:
def f(a: Array[Int]) =
a match {
case Array(x, y, z # _*) => Array(y, x) ++ z
case _ => a
}
Related
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.
Given a sorted sequence of pair, I combine the elements if they are continuous or smaller and skip if they are not.
For example:
if A = Seq((1,2),(3,4),(5,6),(8,10)(11,15))
output should be Seq((1,6),(8,15))
since last element of current entry is continuous with first element of next entry
if B = Seq((1,4),(3,5),(6,7),(9,10)(11,15))
output should be Seq((1,7),(9,15))
since last element of current entry is smaller with first element of next entry
I tried something like:
val finalOut = mySeq.sliding(2).map {
case Array(x, y, _*) => (x, y, (x._2 - y._1))
}.toList
The problem with this is it will just take 2 elements at a time, whereas we need to keep traversing unless there is a gap in continuity. I am not sure how to obtain that in scala.
I tried implementing for loop as well, but that also doesn't help, because it processes one element at a time and doesn't help in keeping a track of other elements or counter like c++.
You can do this with foldRight and accumulate into a new Seq.
This works
val tups1 = Seq((1,2),(3,4),(5,6),(8,10),(11,15))
val tups2 = Seq((1,4),(3,5),(6,7),(9,10),(11,15))
def f(tups: Seq[(Int, Int)]): Seq[(Int, Int)] = {
val emptySeq: Seq[(Int, Int)] = Seq()
tups.foldRight(emptySeq){ (next, accum) => accum match {
case Nil => Seq(next)
case (a, b) +: cs if a - 1 <= next._2 => (next._1, next._2 max b) +: cs
case _ => next +: accum
}}
}
f(tups1) // Seq[(Int, Int)] = List((1,6), (8,15))
f(tups2) // Seq[(Int, Int)] = List((1,7), (9,15))
I'd use foldRight over foldLeft because Seq's are Lists under the hood, and for Lists, prepend is constant, while append is O(n), and foldRight lets you accomplish this with only prepends.
https://docs.scala-lang.org/overviews/collections/performance-characteristics.html
I'm learning Scala by working the exercises from the book "Scala for the Impatient". One exercise asks that:
Write a loop that swaps adjacent elements of an array of integers. For
example, Array(1, 2, 3, 4, 5) becomes Array(2, 1, 4, 3, 5)
I did it in 3 different ways, one of which is as follows.I'm curious if this can be improved as per the comments I've put inline.
def swapWithGrouped(a: Array[Int]) = {
a.grouped(2).map {
// TODO: Can we use reverse here?
case Array(x, y) => Array(y, x)
// TODO: Can we use identity function here?
case Array(x) => Array(x)
}.flatten.toArray
}
You could use .flatMap instead of .map{..}.flatten.
You also don't really need to match a single element array, so you could simply use a variable (although I feel that this really depends on the problem, sometimes showing the symmetry in the patterns is nice and makes the intent more explicit).
So :
scala> def swapWithGrouped(a: Array[Int]) = {
a.grouped(2).flatMap {
case Array(x, y) => Array(y, x)
case single => single
}.toArray
}
swapWithGrouped: (a: Array[Int])Array[Int]
scala> swapWithGrouped(a) // a is Array(1,2,3,4,5)
res0: Array[Int] = Array(2, 1, 4, 3, 5)
The Array(x,y) => Array(y,x) is also pretty easy to read wrong, .reverse makes the intention more explicit and has the added benefit that you can remove the single-element case.
scala> def swapWithGrouped(a: Array[Int]) = a.grouped(2).flatMap(_.reverse).toArray
swapWithGrouped: (a: Array[Int])Array[Int]
No, AFAIK there's no way to bind the patterns to names. The closest thing to doing that is the # operator, but it doesn't work on the pattern as a whole - only on parameters.
On the other hand:
def swapWithGrouped(a: Array[Int]) = {
a.grouped(2).map{ _.reverse }.flatten.toArray
}
should do fine. I'm assuming you don't care about performance; if you do, the code will need to be very different.
Let's consider a simple mapping example:
val a = Array("One", "Two", "Three")
val b = a.map(s => myFn(s))
What I need is to use not myFn(s: String): String here, but myFn(s: String, n: Int): String, where n would be the index of s in a. In this particular case myFn would expect the second argument to be 0 for s == "One", 1 for s == "Two" and 2 for s == "Three". How can I achieve this?
Depends whether you want convenience or speed.
Slow:
a.zipWithIndex.map{ case (s,i) => myFn(s,i) }
Faster:
for (i <- a.indices) yield myFn(a(i),i)
{ var i = -1; a.map{ s => i += 1; myFn(s,i) } }
Possibly fastest:
Array.tabulate(a.length){ i => myFn(a(i),i) }
If not, this surely is:
val b = new Array[Whatever](a.length)
var i = 0
while (i < a.length) {
b(i) = myFn(a(i),i)
i += 1
}
(In Scala 2.10.1 with Java 1.6u37, if "possibly fastest" is declared to take 1x time for a trivial string operation (truncation of a long string to a few characters), then "slow" takes 2x longer, "faster" each take 1.3x longer, and "surely" takes only 0.5x the time.)
A general tip: Use .iterator method liberally, to avoid creation of intermediate collections, and thus speed up your computation. (Only when performance requirements demand it. Or else don't.)
scala> def myFun(s: String, i: Int) = s + i
myFun: (s: String, i: Int)java.lang.String
scala> Array("nami", "zoro", "usopp")
res17: Array[java.lang.String] = Array(nami, zoro, usopp)
scala> res17.iterator.zipWithIndex
res19: java.lang.Object with Iterator[(java.lang.String, Int)]{def idx: Int; def idx_=(x$1: Int): Unit} = non-empty iterator
scala> res19 map { case (k, v) => myFun(k, v) }
res22: Iterator[java.lang.String] = non-empty iterator
scala> res22.toArray
res23: Array[java.lang.String] = Array(nami0, zoro1, usopp2)
Keep in mind that iterators are mutable, and hence once consumed cannot be used again.
An aside: The map call above involves de-tupling and then function application. This forces use of some local variables. You can avoid that using some higher order sorcery - convert a regular function to the one accepting tuple, and then pass it to map.
scala> Array("nami", "zoro", "usopp").zipWithIndex.map(Function.tupled(myFun))
res24: Array[java.lang.String] = Array(nami0, zoro1, usopp2)
What about this? I think it should be fast and it's pretty. But I'm no expert on Scala speed...
a.foldLeft(0) ((i, x) => {myFn(x, i); i + 1;} )
Index can also be accessed via the second element of tuples generated by the zipWithIndex method:
val a = Array("One", "Two", "Three")
val b = a.zipWithIndex.map(s => myFn(s._1, s._2))
I have a 2d array of type boolean (not important)
It is easy to iterate over the array in non-functional style.
How to do it FP style?
var matrix = Array.ofDim[Boolean](5, 5)
for ex, I would like to iterate through all the rows for a given column and return a list of int that would match a specific function.
Example: for column 3, iterate through rows 1 to 5 to return 4, 5 if the cell at (4, 3), (5, 3) match a specif function. Thx v much
def getChildren(nodeId: Int) : List[Int] = {
info("getChildren("+nodeId+")")
var list = List[Int]()
val nodeIndex = id2indexMap(nodeId)
for (rowIndex <- 0 until matrix.size) {
val elem = matrix(rowIndex)(nodeIndex)
if (elem) {
println("Row Index = " + rowIndex)
list = rowIndex :: list
}
}
list
}
What about
(1 to 5) filter {i => predicate(matrix(i)(3))}
where predicate is your function?
Note that initialized with (5,5) indexes goes from 0 to 4.
Update: based on your example
def getChildren(nodeId: Int) : List[Int] = {
info("getChildren("+nodeId+")")
val nodeIndex = id2indexMap(nodeId)
val result = (0 until matrix.size).filter(matrix(_)(nodeIndex)).toList
result.forEach(println)
result
}
You may move the print in the fiter if you want too, and reverse the list if you want it exactly as in your example
If you're not comfortable with filters and zips, you can stick with the for-comprehension but use it in a more functional way:
for {
rowIndex <- matrix.indices
if matrix(rowIndex)(nodeIndex)
} yield {
println("Row Index = " + rowIndex)
rowIndex
}
yield builds a new collection from the results of the for-comprehension, so this expression evaluates to the collection you want to return. seq.indices is a method equivalent to 0 until seq.size. The curly braces allow you to span multiple lines without semicolons, but you can make it in-line if you want:
for (rowIndex <- matrix.indices; if matrix(rowIndex)(nodeIndex)) yield rowIndex
Should probably also mention that normally if you're iterating through an Array you won't need to refer to the indices at all. You'd do something like
for {
row <- matrix
elem <- row
} yield f(elem)
but your use-case is a bit unusual in that it requires the indices of the elements, which you shouldn't normally be concerned with (using array indices is essentially a quick and dirty hack to pair a data element with a number). If you want to capture and use the notion of position you might be better off using a Map[Int, Boolean] or a case class with such a field.
def findIndices[A](aa: Array[Array[A]], pred: A => Boolean): Array[Array[Int]] =
aa.map(row =>
row.zipWithIndex.collect{
case (v,i) if pred(v) => i
}
)
You can refactor it to be a bit more nicer by extracting the function that finds the indices in a single row only:
def findIndices2[A](xs: Array[A], pred: A => Boolean): Array[Int] =
xs.zipWithIndex.collect{
case (v,i) if pred(v) => i
}
And then write
matrix.map(row => findIndices2(row, pred))