I'm a newbie to scala, I'm just writing a simple function to reverse a given string:
def reverse(s: String) : String
for(i <- s.length - 1 to 0) yield s(i)
the yield gives back a scala.collection.immutable.IndexedSeq[Char], and can not convert it to a String. (or is it something else?)
how do i write this function ?
Note that there is already defined function:
scala> val x = "scala is awesome"
x: java.lang.String = scala is awesome
scala> x.reverse
res1: String = emosewa si alacs
But if you want to do that by yourself:
def reverse(s: String) : String =
(for(i <- s.length - 1 to 0 by -1) yield s(i)).mkString
or (sometimes it is better to use until, but probably not in that case)
def reverse(s: String) : String =
(for(i <- s.length until 0 by -1) yield s(i-1)).mkString
Also, note that if you use reversed counting (from bigger one to less one value) you should specify negative step or you will get an empty set:
scala> for(i <- x.length until 0) yield i
res2: scala.collection.immutable.IndexedSeq[Int] = Vector()
scala> for(i <- x.length until 0 by -1) yield i
res3: scala.collection.immutable.IndexedSeq[Int] = Vector(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
Here's a short version
def reverse(s: String) = ("" /: s)((a, x) => x + a)
edit
: or even shorter, we have the fantastically cryptic
def reverse(s: String) = ("" /: s)(_.+:(_))
but I wouldn't really recommend this...
You could also write this using a recursive approach (throwing this one in just for fun)
def reverse(s: String): String = {
if (s.isEmpty) ""
else reverse(s.tail) + s.head
}
As indicated by om-nom-nom, pay attention to the by -1 (otherwise you are not really iterating and your result will be empty). The other trick you can use is collection.breakOut.
It can also be provided to the for comprehension like this:
def reverse(s: String): String =
(for(i <- s.length - 1 to 0 by -1) yield s(i))(collection.breakOut)
reverse("foo")
// String = oof
The benefit of using breakOut is that it will avoid creating a intermediate structure as in the mkString solution.
note: breakOut is leveraging CanBuildFrom and builders which are part of the foundation of the redesigned collection library introduced in scala 2.8.0
All the above answers are correct and here's my take:
scala> val reverseString = (str: String) => str.foldLeft("")((accumulator, nextChar) => nextChar + accumulator)
reverseString: String => java.lang.String = <function1>
scala> reverseString.apply("qwerty")
res0: java.lang.String = ytrewq
def rev(s: String): String = {
val str = s.toList
def f(s: List[Char], acc: List[Char]): List[Char] = s match {
case Nil => acc
case x :: xs => f(xs, x :: acc)
}
f(str, Nil).mkString
}
Here is my version of reversing a string.
scala> val sentence = "apple"
sentence: String = apple
scala> sentence.map(x => x.toString).reduce((x, y) => (y + x))
res9: String = elppa
Related
I search a way to count the different chars from a string.
The problem is that's not allowed to use any functions from the scala-api or to use vars (only val).
I want same result like that
val fruit: String = "dasisteintest"
println(fruit.groupBy(identity).mapValues(_.size))
Map(e -> 2, s -> 3, n -> 1, t -> 3, a -> 1, i -> 2, d -> 1)
In every try I made, I have at the end a list[(Char,Int)] where I have to change the Int. But because it's an immutable list I can't change it.
How can I implement that counting char algorithm?
You can use the following snippet:
val fruit: String = "dasisteintest"
val map = scala.collection.mutable.HashMap.empty[Char, Int]
for (symbol <- fruit) {
if (map.contains(symbol))
map(symbol) = map(symbol) + 1
else
map.+=((symbol, 1))
}
println(map)
def countChars(str: String) = {
def loop(chars: List[Char], acc: Map[Char, Int]): Map[Char, Int] = {
chars match {
case Nil => acc
case char :: rest =>
loop(rest, acc + (char -> (acc(char) + 1)))
}
}
loop(str.toList, Map.empty[Char, Int] withDefaultValue 0)
}
Test:
# val fruit: String = "dasisteintest"
fruit: String = "dasisteintest"
# countChars(fruit)
res4: Map[Char, Int] = Map('e' -> 2, 's' -> 3, 'n' -> 1, 't' -> 3, 'a' -> 1, 'i' -> 2, 'd' -> 1)
Whatever you use here is from scala api, a Map.apply, or Map.empty or List.::. It would be difficult not to use any functions from scala api. My guess is that you aren't supposed to be using things like groupBy and you are supposed to do something a bit more low level. Folding is natural solution here, like foldLeft, but if that is considered "using a function from scala api", you can just implement foldLeft yourself, just like I did in my solution.
As for withDefaultValue you can replace it with explicit check if value is present and put a 1 there in that case.
You don't know how to change an in a list or map that is immutable? You just make a new list with that value changed.
For a map, given
val map = Map('a' -> 3)
you can update it doing
# map.updated('a', 4)
res6: Map[Char, Int] = Map('a' -> 4)
or
# map + ('a' -> 4)
res7: Map[Char, Int] = Map('a' -> 4)
Both do exact the same thing - insert or update - and return new map.
Here you can find how to update elements in a list
Replace element in List with scala
although you rarely want to access list by index, you rather just build a new list from old one while iterating over it somehow, e.g. with fold.
What do you mean by "no functions from Scala API"? Does that include no functions from the collections api? If so, then ignore my answer. However if we can't even use reduce methods, I don't see the point of this exercise.
Here's what I came up with:
val fruit: String = "dasisteintest"
fruit.foldLeft[Map[Char,Int]](Map.empty)((map, c) => map + (c -> (map.getOrElse(c, 0) + 1)))
Although can you expand what you mean by ""you have to change the Int"?
Here is the expected code.
First the function which returns the char from the list
def removeFromList(l: List[Char], l2: List[Char], toDelete: Char): List[Char] = {
if (l.isEmpty) l2
else {
if (l.head == toDelete)
removeFromList(l.tail, l2, toDelete)
else
removeFromList(l.tail, l2 :+ l.head, toDelete)
}
}
and then the function which counts the chars and calls removeFromList()
def zaehlZeichen(s: String): List[(Char, Int)] = {
val sl: List[Char] = s.toUpperCase().toList
if (sl.isEmpty) Nil
else {
val l: List[Char] = List()
val tupleList: List[(Char, Int)] = List();
val in: Int = countChar(sl, 0, sl.head)
val t: List[(Char, Int)] = tupleList :+ (sl.head, in)
val cutL: List[Char] = removeFromList(sl, l, sl.head)
t ::: zaehlZeichen(cutL.mkString);
}
}
object CountEachCharInString
{
//Counts the number of a specific character in the Input String
def characterCount(inputChar: Char, str: String): Unit =
{
var num: Int = 0
num = str.count(_ == inputChar);
/*
//Implementation of count method
for(i <- 0 to str.length - 1)
{
if(str(i) == inputChar)
{
num += 1
}
}
*/
println(s"$inputChar appears $num times")
}
def countAllChars(inputStr: String): Unit =
{
//To eliminate duplicates, need one loop inside the other. str(i) == str(j)
for(i <- 0 to inputStr.length - 1)
{
var occurence: Int = 0
for(j <- 0 to i-1)
{
if(inputStr(j) == inputStr(i))
occurence = occurence + 1
}
if(occurence == 0)
{
characterCount(inputStr(i), inputStr)
//var num = inputStr.count(_ == inputStr(i))
//println( inputStr(i) + s" appears $num times")
}
}
}
def main(args: Array[String]): Unit =
{
countAllChars("HelloforHello...^^&&&&")
}
}
I'm getting this error when i run the below code -
type mismatch, found : scala.collection.immutable.IndexedSeq[Int] required: Range
Where I'm going wrong ?
Functions -
def calcRange(i: Int, r: List[Range]):List[Range] = r match {
case List() => List(new Range(i,i+1,1))
case r1::rs =>
if (r1.start-1==i) {new Range(i,r1.end,1):: rs; }
else if(r1.end==i){new Range(r1.start,r1.end+1,1)::rs}
else {r1::calcRange(i,rs)}
}
def recurseForRanges(l: Iterator[Int]):List[Range] = {
var ans=List[Range]()
while(l.hasNext){
val cur=l.next;
ans=calcRange(cur,ans)
}
ans
}
def rangify(l: Iterator[Int]):Iterator[Range] = recurseForRanges(l).toIterator
Driver code
def main(args: Array[String]) {
val x=rangify( List(1,2,3,6,7,8).toIterator ).reduce( (x,y) => x ++ y)
/** This line gives the error -type mismatch,
found : scala.collection.immutable.IndexedSeq[Int] required: Range */
}
You can check docs:
++[B](that: GenTraversableOnce[B]): IndexedSeq[B]
++ returns IndexedSeq, not another Range, Range cannot have "holes" in them.
One way to fix it is to change Ranges to IndexedSeqs before reducing. This upcasts the Range so that reduce could take function
(IndexedSeq[Int], IndexedSeq[Int]) => IndexedSeq[Int]
because now it takes
(Range, Range) => Range
But ++ actually returns IndexedSeq[Int] instead of Range hence the type error.
val x = rangify(List(1, 2, 3, 6, 7, 8).iterator).map(_.toIndexedSeq).reduce(_ ++ _)
You can as well do this kind of cast by annotating type:
val it: Iterator[IndexedSeq[Int]] = rangify(List(1,2,3,6,7,8).iterator)
val x = it.reduce(_ ++ _)
Note that your code can be simplified, without vars
def calcRange(r: List[Range], i: Int): List[Range] = r match {
case Nil =>
Range(i, i + 1) :: Nil
case r1 :: rs =>
if (r1.start - 1 == i)
Range(i, r1.end) :: rs
else if (r1.end == i)
Range(r1.start, r1.end + 1) :: rs
else
r1 :: calcRange(rs, i)
}
def recurseForRanges(l: Iterator[Int]): List[Range] = {
l.foldLeft(List.empty[Range])(calcRange)
}
def rangify(l: Iterator[Int]): Iterator[Range] = recurseForRanges(l).iterator
val x = rangify(List(1,2,3,6,7,8).iterator).map(_.toIndexedSeq).reduce(_ ++ _)
To explain what I've done with it:
Range has a factory method, you don't need new keyword, you don't need to specify by value because 1 is default.
You need no semicolons as well.
What you are doing in recurseForRanges is basically what foldLeft does, I just swapped arguments in calcRange it could be passed directly to foldLeft.
I'm trying to write an algorithm that returns the closest value within a list of values. So in a List(4.0, 6.0, 2.0) the closest value to 7.0 is 6.0
Below is the code I'm using but it's not correct as the closest value being returned is 4 :
How can fix below code or is there a Scala utility method I can use to solve this ?
val num = 7.0 //> num : Double = 7.0
val listNums = List[Double](4,6,2) //> listNums : List[Double] = List(4.0, 6.0, 2.0)
def getClosest(num : Double , listNums : List[Double]) = {
var min = java.lang.Double.MAX_VALUE
var closest = num
for(x <- listNums ){
val diff = x - num
if(num < min){
min = diff
closest = x
}
}
closest
} //> getClosest: (num: Double, listNums: List[Double])Double
val closest = getClosest(num , listNums) //> closest : Double = 4.0
This is almost a one-liner with minBy:
def getClosest(num: Double, listNums: List[Double]) =
listNums.minBy(v => math.abs(v - num))
minBy is unfortunately a partial function—it'll crash with an exception when called on an empty list. To match the behavior of your implementation, you can write the following:
def getClosest(num: Double, listNums: List[Double]) = listNums match {
case Nil => Double.MaxValue
case list => list.minBy(v => math.abs(v - num))
}
The problem with your code is that you're not taking the absolute value, as the other answer implicitly points out. Don't use Math.abs, though—that's shorthand for java.lang.Math.abs. math.abs is more idiomatic.
A simple implementation would be:
def getClosest(num : Double , list : List[Double]) :Double = list match {
case x :: xs => list.foldLeft(x){(ans,next) =>
if(math.abs(next - num) < math.abs(ans - num)) next else ans }
case Nil => throw new RuntimeException("Empty list")
}
scala> getClosest(20, List(1,19,22,24))
res0: Double = 19.0
A more general implementation would be:
def getClosest[A: Numeric](num: A, list: List[A]): A = {
val im = implicitly[Numeric[A]]
list match {
case x :: xs => list.minBy (y => im.abs(im.minus(y, num)))
case Nil => throw new RuntimeException("Empty list")
}
}
Thanks to #Travis for suggesting minBy. It is much more prettier than foldLeft
Define an Ordering by distance from your selected number, and use the min mathod from List applying this ordering.
I don't have a scala install handy right now to provide a coded tested solution, but the two pieces of this are relatively easy.
If you want to be more generic, you can try this:
def getClosest[A: Numeric](value: A, elems: Traversable[A]): A = {
val ops = implicitly[Numeric[A]]
elems.minBy(e => ops.abs(ops.minus(e, value)))
}
Then:
getClosest(20, List(1, 19, 22, 24))
//> res1: Int = 19
getClosest(BigDecimal("5000000000000000"), List(BigDecimal(1), BigDecimal(19)))
//> res2: scala.math.BigDecimal = 19
Here is the code I have which looks ugly because it uses two vars.
def patternMatching(pattern: String, genome: String): List[Int] = {
assert(pattern.length < genome.length)
var curr = 0
var r = List[Int]()
while (curr != -1) {
curr = genome.indexOf(pattern, curr)
if (curr != -1) {
r ::= curr
curr += 1
}
}
r.reverse
}
How do you write this in a functional way?
It's quite straigthforward :
0.until(genome.length).filter(genome.startsWith(pattern, _))
You could use unfold method from scalaz like this:
import scalaz._, Scalaz._
def patternIndexes(pattern: String, genome: String) = unfold(0){
genome.indexOf(pattern, _) match {
case -1 => None
case n => (n, n+1).some
}
}
Usage:
scala> patternIndexes("a", "aba").toList
res0: List[Int] = List(0, 2)
There is a much simpler idiomatic Scala solution that does not require trying to explicitly apply a pattern at every location or using 3rd party library:
def patternMatching(pattern: String, genome: String): List[Int] =
pattern.r.findAllMatchIn(genome).map(_.start).toList
If you require to know also the ending position of the index you could use:
def patternMatchingIndex(pattern: Regex, text: String): List[(Int, Int)] =
pattern.findAllMatchIn(text).map(index => (index.start, index.end)).toList
In Scala, is there a way to get the currently evaluated items in a Stream? For example in the Stream
val s: Stream[Int] = Stream.cons(1, Stream.cons(2, Stream.cons(3, s.map(_+1))))
the method should return only List(1,2,3).
In 2.8, there is a protected method called tailDefined that will return false when you get to the point in the stream that has not yet been evaluated.
This isn't too useful (unless you want to write your own Stream class) except that Cons itself makes the method public. I'm not sure why it's protected in Stream and not in Cons--I would think one or the other might be a bug. But for now, at least, you can write a method like so (writing a functional equivalent is left as an exercise to the reader):
def streamEvalLen[T](s: Stream[T]) = {
if (s.isEmpty) 0
else {
var i = 1
var t = s
while (t match {
case c: Stream.Cons[_] => c.tailDefined
case _ => false
}) {
i += 1
t = t.tail
}
i
}
}
Here you can see it in action:
scala> val s = Stream.iterate(0)(_+1)
s: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> streamEvalLen(s)
res0: Int = 1
scala> s.take(3).toList
res1: List[Int] = List(0, 1, 2)
scala> s
res2: scala.collection.immutable.Stream[Int] = Stream(0, 1, 2, ?)
scala> streamEvalLen(s)
res3: Int = 3
The solution based on Rex's answer:
def evaluatedItems[T](stream: => Stream[T]): List[T] = {
#tailrec
def inner(s: => Stream[T], acc: List[T]): List[T] = s match {
case Empty => acc
case c: Cons[T] => if (c.tailDefined) {
inner(c.tail, acc ++ List(c.head))
} else { acc ++ List(c.head) }
}
inner(stream, List())
}
Type that statement into the interactive shell and you will see that it evaluates to s: Stream[Int] = Stream(1, ?). So, in fact, the other two elements of 2 and 3 are not yet known.
As you access further elements, more of the stream is calculated. So, now put s(3) into the shell, which will return res0: Int = 2. Now put s into the shell and you will see the new value res1: Stream[Int] = Stream(1, 2, 3, 2, ?).
The only method I could find that contained the information that you wanted was, unfortunately, s.toString. With some parsing you will be able to get the elements back out of the string. This is a barely acceptable solution with just ints and I couldn't imagine any generic solution using the string parsing idea.
Using scanLeft
lazy val s: Stream[Int] = 1 #:: s.scanLeft(2) { case (a, _) => 1 + a }