I have a Vector and I'd like to find neighbors of given element.
Say if we have Vector(1, 2, 3, 4, 5) and then:
for element 2, result must be Some((1, 3))
for element 5, result must be Some((4, 1))
for element 1, result must be Some((5, 2))
for element 6, result must be None
and so on..
I have not found any solution in standard lib(please point me if there is one), so got the next one:
implicit class VectorOps[T](seq: Vector[T]) {
def findNeighbors(elem: T): Option[(T, T)] = {
val currentIdx = seq.indexOf(elem)
val firstIdx = 0
val lastIdx = seq.size - 1
seq match {
case _ if currentIdx == -1 || seq.size < 2 => None
case _ if seq.size == 2 => seq.find(_ != elem).map(elem => (elem, elem))
case _ if currentIdx == firstIdx => Some((seq(lastIdx), seq(currentIdx + 1)))
case _ if currentIdx == lastIdx => Some((seq(currentIdx - 1), seq(firstIdx)))
case _ => Some((seq(currentIdx - 1), seq(currentIdx + 1)))
}
}
}
The question is: how this can be simplified/optimized using stdlib?
def neighbours[T](v: Seq[T], x: T): Option[(T, T)] =
(v.last +: v :+ v.head)
.sliding(3, 1)
.find(_(1) == x)
.map(x => (x(0), x(2)))
This uses sliding to create a 3 element window in the data and uses find to match the middle value of the 3. Adding the last/first to the input deals with the wrap-around case.
This will fail if the Vector is too short so needs some error checking.
This version is safe for all input
def neighbours[T](v: Seq[T], x: T): Option[(T, T)] =
(v.takeRight(1) ++ v ++ v.take(1))
.sliding(3, 1)
.find(_(1) == x)
.map(x => (x(0), x(2)))
Optimal when number of calls with the same sequence is about or more than seq.toSet.size:
val elementToPair = seq.indicies.map(i => seq(i) ->
(seq((i - 1 + seq.length) % seq.length), seq((i + 1 + seq.length) % seq.length)
).toMap
elementToPair.get(elem)
// other calls
Optimal when number of calls with the same sequence less than seq.toSet.size:
Some(seq.indexOf(elem)).filterNot(_ == -1).map { i =>
(seq((i - 1 + seq.length) % seq.length), seq((i + 1 + seq.length) % seq.length) }
I'm trying to solve problem longest palindromic substring in leetcode in a functional way (using LazyList as cache). However, I got TLE result and I don't know why. Can anyone explain why this code is not efficient?
object Solution {
def longestPalindrome(s: String): String = {
val n = s.length
var ans = (0, 0)
var cnt = 1
def logic(i: Int, j: Int): Int = (i, j) match {
case (i, j) if i > j => -1
case (i, j) if i == j => 1
case (i, j) if s(i) != s(j) => 0
case (i, j) if i + 1 == j => 2
case (i, j) =>
if(mem(i + 1)(j - 1) == 0) 0
else j - i + 1
}
lazy val mem: LazyList[LazyList[Int]] = LazyList.tabulate(n, n) {
case (i, j) => {
val n = logic(i, j)
if(n > cnt) {
cnt = n
ans = (i, j)
}
n
}
}
mem.foreach(_.force)
// println(mem)
ans match {
case (i, j) => s.slice(i, j + 1)
}
}
}
Suppose, I have a log file of events (page visits) with a timestamp. I'd like to group events into sessions where I consider that events belong to the same session when they are not further than X minutes from each other.
Currently, I ended up with this algorithm.
val s = List(1000, 501, 500, 10, 3, 2, 1) // timestamps
val n = 10 // time span
import scala.collection.mutable.ListBuffer
(s.head +: s).sliding(2).foldLeft(ListBuffer.empty[ListBuffer[Int]]) {
case (acc, List(a, b)) if acc.isEmpty =>
acc += ListBuffer(a)
acc
case (acc, List(a, b)) =>
if (n >= a - b) {
acc.last += b
acc
} else {
acc += ListBuffer(b)
acc
}
}
The result
ListBuffer(ListBuffer(1000), ListBuffer(501, 500), ListBuffer(10, 3, 2, 1))
Is there any better/functional/efficient way to do it?
Slightly adapting this answer by altering the condition ...
s.foldRight[List[List[Int]]](Nil)((a, b) => b match {
case (bh # bhh :: _) :: bt if (bhh + n >= a) => (a :: bh) :: bt
case _ => (a :: Nil) :: b
})
I am trying to parallelize recursive calls of sudoku solver from 25 lines Sudoku solver in Scala. I've changed their Fold into reduce
def reduce(f: (Int, Int) => Int, accu: Int, l: Int, u: Int): Int = {
accu + (l until u).toArray.reduce(f(accu, _) + f(accu, _))
}
which if run sequentially works fine, but when I change it into
accu + (l until u).toArray.par.reduce(f(accu, _) + f(accu, _))
the recursion reaches the bottom much more often and generates false solutions. I thought, that it will execute the bottom level recursion and work it's way up, but doesn't seem to do so.
I've also tried futures
def parForFut2(f: (Int, Int) => Int, accu: Int, l: Int, u: Int): Int = {
var sum: Int = accu
val vals = l until u
vals.foreach(t => scala.actors.Futures.future(sum + f(accu, t)))
sum
}
which appears to have the same problem as the par.reduce. I would appreciate any comment. The whole code is here:
object SudokuSolver extends App {
// The board is represented by an array of string
val source = scala.io.Source.fromFile("./puzzle")
val lines = (source.getLines).toArray
var m: Array[Array[Char]] = for (
str <- lines;
line: Array[Char] = str.toArray
) yield line
source.close()
// For printing m
def print = {
Console.println("");
refArrayOps(m) map (carr => Console.println(new String(carr)))
}
// The test for validity of n on position x,y
def invalid(i: Int, x: Int, y: Int, n: Char): Boolean =
i < 9 && (m(y)(i) == n || m(i)(x) == n ||
m(y / 3 * 3 + i / 3)(x / 3 * 3 + i % 3) == n || invalid(i + 1, x, y, n))
// Looping over a half-closed range of consecutive Integers [l..u)
// is factored out Into a higher-order function
def parReduce(f: (Int, Int) => Int, accu: Int, l: Int, u: Int): Int = {
accu + (l until u).toArray.par.reduce(f(accu, _) + f(accu, _))
}
// The search function examines each position on the board in turn,
// trying the numbers 1..9 in each unfilled position
// The function is itself a higher-order fold, accumulating the value
// accu by applying the given function f to it whenever a solution m
// is found
def search(x: Int, y: Int, f: (Int) => Int, accu: Int): Int = Pair(x, y) match {
case Pair(9, y) => search(0, y + 1, f, accu) // next row
case Pair(0, 9) => f(accu) // found a solution - print it and continue
case Pair(x, y) => if (m(y)(x) != '0') search(x + 1, y, f, accu) else
parForFut1((accu: Int, n: Int) =>
if (invalid(0, x, y, (n + 48).asInstanceOf[Char])) accu else {
m(y)(x) = (n + 48).asInstanceOf[Char];
val newaccu = search(x + 1, y, f, accu);
m(y)(x) = '0';
newaccu
}, accu, 1, 10)
}
// The main part of the program uses the search function to accumulate
// the total number of solutions
Console.println("\n" + search(0, 0, i => { print; i + 1 }, 0) + " solution(s)")
}
As far as I can tell, recursion is inherently sequential (i.e. not parallelizable).
I'd reason it like this: recursion means (put simply) 'call myself'. A function call always happens within one and exactly one thread.
If you are telling the function to call itself, then you are staying in that thread - you're not dividing the work (i.e. making it parallel).
Recursion and parallelism are related though, but not at the function-call level. They are related in the sense that tasks can be recursively decomposed into smaller parts, that can be performed in parallel.
After Andreas comment I changed the m: Array[Array[Char]] into m: List[List[Char]] which prevents any unnecessary and unwanted changes to it. The final looping method is
def reduc(f: (Int, Int) => Int,
accu: Int, l: Int, u: Int, m1: List[List[Char]]):Int =
accu + (l until u).toArray.par.reduce(f(accu, _) + f(accu, _))
and I had to pass m as an argument to each used function, so every one of them had its own instance of it. The whole code:
object SudokuSolver extends App{
// The board is represented by an Array of strings (Arrays of Chars),
val source = scala.io.Source.fromFile("./puzzle")
val lines = source.getLines.toList
val m: List[List[Char]] = for (
str <- lines;
line: List[Char] = str.toList
) yield line
source.close()
// For prInting m
def printSud(m: List[List[Char]]) = {
Console.println("")
m map (println)
}
Console.println("\nINPUT:")
printSud(m)
def invalid(i:Int, x:Int, y:Int, n:Char,m1: List[List[Char]]): Boolean =
i < 9 && (m1(y)(i) == n || m1(i)(x) == n ||
m1(y / 3 * 3 + i / 3)(x / 3 * 3 + i % 3) == n ||
invalid(i + 1, x, y, n, m1))
def reduc(f: (Int, Int) => Int, accu: Int, l: Int, u: Int,
m1: List[List[Char]]): Int =
accu + (l until u).toArray.par.reduce(f(accu, _) + f(accu, _))
def search(x: Int, y: Int, accu: Int, m1: List[List[Char]]): Int =
Pair(x, y) match {
case Pair(9, y) => search(0, y + 1, accu, m1) // next row
case Pair(0, 9) => { printSud(m1); accu + 1 } // found a solution
case Pair(x, y) =>
if (m1(y)(x) != '0')
search(x + 1, y, accu, m1) // place is filled, we skip it.
else // box is not filled, we try all n in {1,...,9}
reduc((accu: Int, n: Int) => {
if (invalid(0, x, y, (n + 48).asInstanceOf[Char], m1))
accu
else { // n fits here
val line = List(m1(y).patch(x, Seq((n + 48).asInstanceOf[Char]), 1))
val m2 = m1.patch(y, line, 1)
val newaccu = search(x + 1, y, accu, m2);
val m3 = m1.patch(y, m1(y).patch(x, Seq(0), 1), 1)
newaccu
}
}, accu, 1, 10, m1)
}
Console.println("\n" + search(0, 0, 0, m) + " solution(s)")
}
I'd like to convert a single value into a collection of multiple "characteristics", without using a mutable data structure to collect the values. I'd like something like this fantasy construct which uses pattern matching, but does not stop after first match:
scala> 2 multimatch {
case i if i > 0 => "Positive"
case i if i < 0 => "Negative"
case i if (i % 2 == 0) => "Even"
//yadda yadda
}
res0: Seq[java.lang.String] = List(Positive, Even)
Using the pimp pattern, partial functions and repeated parameters, this is how close I can get:
class MultiMatcher[A](a: A) {
def multiMatch[B](pfs: PartialFunction[A, B]*): Seq[B] = {
pfs.map(_.lift(a)).collect{ case Some(v) => v }
}
}
implicit def toMultiMatcher[A](a:A): MultiMatcher[A] = new MultiMatcher(a)
2 multiMatch (
{ case i if i > 0 => "Positive" },
{ case i if i < 0 => "Negative" },
{ case i if i % 2 == 0 => "Even" }
)
// returns Seq[java.lang.String] = ArrayBuffer(Positive, Even)
First you define your characteristics as functions from Int to Option[String]
val pos = (i:Int) => if (i > 0) Some("Positive") else None
val neg = (i:Int) => if (i < 0) Some("Negative") else None
val even = (i:Int) => if (i % 2 == 0) Some("Even") else None
Then you make a list of characteristics.
val characteristics = pos::neg::even::Nil
And then you use flatmap to get a list of those characteristics that apply to a certain object.
scala> characteristics.flatMap(f=>f(2))
res6: List[java.lang.String] = List(Positive, Even)
First, define a multimatch function as follows:
scala> def multimatch[A,B]( value : A,ps: ( A => Boolean, B)*) =
| for ( p <- ps
| if (p._1(value))) yield p._2
multimatch: [A,B](value: A,ps: ((A) => Boolean, B)*)Seq[B]
Then, here we go:
scala> multimatch(2,
| ( ((x :Int) => x > 0) -> "POSITIVE"),
| ( ((x :Int) => x < 0) -> "NEGATIVE"),
| ( ((x :Int) => x % 2 == 0) -> "EVEN")
| )
res4: Seq[java.lang.String] = ArrayBuffer(POSITIVE, EVEN)
Or, less cluttered:
scala> multimatch(2,
| ( (x :Int) => x > 0 , "POSITIVE"),
| ( (x :Int) => x < 0, "NEGATIVE"),
| ( (x :Int) => x % 2 == 0, "EVEN")
| )
res5: Seq[java.lang.String] = ArrayBuffer(POSITIVE, EVEN)