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...^^&&&&")
}
}
Related
I have a Scala list below :
val numList = List(1,2,3,4,5,1,2)
I want to get index of the same element pair in the list. The output should look like (0,5),(1,6)
How can I achieve using map?
def catchDuplicates(num : List[Int]) : (Int , Int) = {
val count = 0;
val emptyMap: HashMap[Int, Int] = HashMap.empty[Int, Int]
for (i <- num)
if (emptyMap.contains(i)) {
emptyMap.put(i, (emptyMap.get(i)) + 1) }
else {
emptyMap.put(i, 1)
}
}
Let's make the challenge a little more interesting.
val numList = List(1,2,3,4,5,1,2,1)
Now the result should be something like (0, 5, 7),(1, 6), which makes it pretty clear that returning one or more tuples is not going to be feasible. Returning a List of List[Int] would make much more sense.
def catchDuplicates(nums: List[Int]): List[List[Int]] =
nums.zipWithIndex //List[(Int,Int)]
.groupMap(_._1)(_._2) //Map[Int,List[Int]]
.values //Iterable[List[Int]]
.filter(_.lengthIs > 1)
.toList //List[List[Int]]
You might also add a .view in order to minimize the number of traversals and intermediate collections created.
def catchDuplicates(nums: List[Int]): List[List[Int]] =
nums.view
.zipWithIndex
.groupMap(_._1)(_._2)
.collect{case (_,vs) if vs.sizeIs > 1 => vs.toList}
.toList
How can I achieve using map?
You can't.
Because you only want to return the indexes of the elements that appear twice; which is a very different kind of transformation than the one that map expects.
You can use foldLeft thought.
object catchDuplicates {
final case class Result[A](elem: A, firstIdx: Int, secondIdx: Int)
private final case class State[A](seenElements: Map[A, Int], duplicates: List[Result[A]]) {
def next(elem: A, idx: Int): State[A] =
seenElements.get(key = elem).fold(
ifEmpty = this.copy(seenElements = this.seenElements + (elem -> idx))
) { firstIdx =>
State(
seenElements = this.seenElements.removed(key = elem),
duplicates = Result(elem, firstIdx, secondIdx = idx) :: this.duplicates
)
}
}
private object State {
def initial[A]: State[A] =
State(
seenElements = Map.empty,
duplicates = List.empty
)
}
def apply[A](data: List[A]): List[Result[A]] =
data.iterator.zipWithIndex.foldLeft(State.initial[A]) {
case (acc, (elem, idx)) =>
acc.next(elem, idx)
}.duplicates // You may add a reverse here if order is important.
}
Which can be used like this:
val numList = List(1,2,3,4,5,1,2)
val result = catchDuplicates(numList)
// result: List[Result] = List(Result(2,1,6), Result(1,0,5))
You can see the code running here.
I think returning tuple is not a good option instead you should try Map like -
object FindIndexOfDupElement extends App {
val numList = List(1, 2, 3, 4, 5, 1, 2)
#tailrec
def findIndex(elems: List[Int], res: Map[Int, List[Int]] = Map.empty, index: Int = 0): Map[Int, List[Int]] = {
elems match {
case head :: rest =>
if (res.get(head).isEmpty) {
findIndex(rest, res ++ Map(head -> (index :: Nil)), index + 1)
} else {
val updatedMap: Map[Int, List[Int]] = res.map {
case (key, indexes) if key == head => (key, (indexes :+ index))
case (key, indexes) => (key, indexes)
}
findIndex(rest, updatedMap, index + 1)
}
case _ => res
}
}
println(findIndex(numList).filter(x => x._2.size > 1))
}
you can clearly see the number(key) and respective index in the map -
HashMap(1 -> List(0, 5), 2 -> List(1, 6))
For example, I have a Map[Integer,String] like
val map = Map(1 -> "a", 2 -> "b", 3 -> "c", 5 -> "d", 9 -> "e", 100 -> "z")
If given key is 2, then "b" is expected to return.
If given key is 50, then "e" and "z" are expected to return.
If given key is 0, then "a" is expected to return.
In other words, if the key exists in the Map the corresponding value should be returned. Otherwise the values of the closest smaller and larger keys should be returned (in the case no other key is smaller only the value of the closest larger key should be returned and vice versa).
How can this be accomplished?
Map doesn't preserve order hence I would suggest creating a method that:
converts the Map into a TreeMap
generates the lower/upper Map entries as Options in a list using to(key).lastOption and from(key).headOption, respectively
flattens the list and extracts the Map values:
Sample code as follows:
val map = Map(1->"a", 2->"b", 100->"z", 9->"e", 3->"c", 5->"d")
def closestValues(m: Map[Int, String], key: Int): Seq[String] = {
import scala.collection.immutable.TreeMap
val tm = TreeMap(m.toSeq: _*)
Seq( tm.to(key).lastOption, tm.from(key).headOption ).
flatten.distinct.map{ case (k, v) => v }
}
closestValues(map, 0)
// res1: Seq[String] = List(a)
closestValues(map, 2)
// res2: Seq[String] = List(b)
closestValues(map, 50)
// res3: Seq[String] = List(e, z)
closestValues(map, 101)
// res4: Seq[String] = List(z)
UPDATE:
Starting Scala 2.13, methods to and from for TreeMap are replaced with rangeTo and rangeFrom, respectively.
My 2-cents worth.
def getClose[K](m: Map[Int,K], k: Int): Seq[K] =
if (m.get(k).nonEmpty) Seq(m(k))
else {
val (below,above) = m.keys.partition(_ < k)
Seq( if (below.isEmpty) None else Some(below.max)
, if (above.isEmpty) None else Some(above.min)
).flatten.map(m)
}
I would recommend first converting the Map to a SortedMap since the order of the keys needs to be taken into account.
val map = Map(1->"a",2->"b",3->"c",5->"d",9->"e",100->"z")
val sortedMap = SortedMap[Int, String]() ++ map
After that, use the following method to get the closest values. The result is returned as a List.
def getClosestValue(num: Int) = {
if (sortedMap.contains(num)) {
List(sortedMap(num))
} else {
lazy val larger = sortedMap.filterKeys(_ > num)
lazy val lower = sortedMap.filterKeys(_ < num)
if (larger.isEmpty) {
List(sortedMap.last._2)
} else if (lower.isEmpty) {
List(sortedMap.head._2)
} else {
List(lower.last._2, larger.head._2)
}
}
}
Testing it with the following values:
println(getClosestValue(2))
println(getClosestValue(50))
println(getClosestValue(0))
println(getClosestValue(101))
will give
List(b)
List(z, e)
List(a)
List(z)
This not an efficient solution but you can do something like below
val map =Map(1->"a",2->"b",3->"c",5->"d",9->"e",100->"z")
val keyset = map.keySet
def getNearestValues(key: Int) : Array[String] = {
if(keyset.contains(key)) Array(map(key))
else{
var array = Array.empty[String]
val less = keyset.filter(_ < key)
if(!less.isEmpty) array = array ++ Array(map(less.toList.sortWith(_ < _).last))
val greater = keyset.filter(_ > key)
if(!greater.isEmpty) array = array ++ Array(map(greater.toList.sortWith(_ < _).head))
array
}
}
A small bit of functional way
val map =Map(1->"a",2->"b",3->"c",5->"d",9->"e",100->"z")
val keyset = map.keySet
def getNearestValues(key: Int) : Array[String] = keyset.contains(key) match {
case true => Array(map(key))
case false => {
val (lower, upper) = keyset.toList.sortWith(_ < _).span(x => x < key)
val lowArray = if(lower.isEmpty) Array.empty[String] else Array(map(lower.last))
val upperArray = if(upper.isEmpty) Array.empty[String] else Array(map(upper.head))
lowArray ++ upperArray
}
}
getNearestValues(0) should return Array(a) and getNearestValues(50) should return Array(e, z) and getNearestValues(9) should return Array(e)
You can solve this problem with the complexity smaller that in any proposed solutions above . So, if performance is critical, check this answer.
Another Scala solution
val m = Map(1 -> "a", 2 -> "b", 3 -> "c", 5 -> "d", 9 -> "e", 100 -> "z")
List(0, 2, 50, 101).foreach { i => {
val inp = i
val (mn, mx) = if (m.get(inp).nonEmpty) (Map(inp -> m(inp)), Map(inp -> m(inp))) else m.partition(x => x._1 > inp)
(mn, mx) match {
case (x, y) if y.isEmpty => println(m(mn.keys.min))
case (x, y) if x.isEmpty => println(m(mx.keys.max))
case (x, y) if y == x => println(m(inp))
case (x, y) => println(m(mn.keys.min), m(mx.keys.max))
}
}
}
Results:
a
b
(z,e)
z
Want to improve piece of code by folding operation
this code works
var r = 0
arr.foreach { s =>
val count = arr.count(_ == s)
if (count > r) r = count
}
But in case with fold. I have an error with types.
Error:(44, 49) type mismatch;
found : (Int, String) => Any
required: (Any, Any) => Any
arr.fold(0: Int)((result: Int, s: String) => {
^
arr.fold(0: Int)((result: Int, s: String) => {
val count = arr.count(_ == s)
if (count > result) count
})
What is wrong ?
If you're trying to find the string with most occurrences in the the array, you can use groupBy:
val arr = Array("yuval", "yuval", "david")
arr.groupBy(identity).mapValues(_.length).max._2
arr: Array[String] = Array(yuval, yuval, david)
res1: Int = 2
If you really want to jump to hoops of using fold, you'll either need foldLeft or foldRight which pass the accumulator along for each value in the sequence:
val arr = Array("yuval", "yuval", "david")
val aggregatedMap = arr.foldLeft(Map.empty[String, Int].withDefaultValue(0)) {
case (map, value) => map.updated(value, map(value) + 1)
}
println(aggregatedMap.max._2)
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
I think this might be a common operation. So maybe it's inside the API but I can't find it. Also I'm interested in an efficient functional/simple solution if not.
Given a sequence of tuples ("a" -> 1, "b" ->2, "c" -> 3) I want to turn it into a map. That's easy using TraversableOnce.toMap. But I want to fail this construction if the resulting map "would contain a contradiction", i.e. different values assigned to the same key. Like in the sequence ("a" -> 1, "a" -> 2). But duplicates shall be allowed.
Currently I have this (very imperative) code:
def buildMap[A,B](in: TraversableOnce[(A,B)]): Option[Map[A,B]] = {
val map = new HashMap[A,B]
val it = in.toIterator
var fail = false
while(it.hasNext){
val next = it.next()
val old = map.put(next._1, next._2)
fail = old.isDefined && old.get != next._2
}
if(fail) None else Some(map.toMap)
}
Side Question
Is the final toMap really necessary? I get a type error when omitting it, but I think it should work. The implementation of toMap constructs a new map which I want to avoid.
As always when working with Seq[A] the optimal solution performance-wise depends on the concrete collection type.
A general but not very efficient solution would be to fold over an Option[Map[A,B]]:
def optMap[A,B](in: Iterable[(A,B)]): Option[Map[A,B]] =
in.iterator.foldLeft(Option(Map[A,B]())) {
case (Some(m),e # (k,v)) if m.getOrElse(k, v) == v => Some(m + e)
case _ => None
}
If you restrict yourself to using List[A,B]s an optimized version would be:
#tailrec
def rmap[A,B](in: List[(A,B)], out: Map[A,B] = Map[A,B]()): Option[Map[A,B]] = in match {
case (e # (k,v)) :: tail if out.getOrElse(k,v) == v =>
rmap(tail, out + e)
case Nil =>
Some(out)
case _ => None
}
Additionally a less idiomatic version using mutable maps could be implemented like this:
def mmap[A,B](in: Iterable[(A,B)]): Option[Map[A,B]] = {
val dest = collection.mutable.Map[A,B]()
for (e # (k,v) <- in) {
if (dest.getOrElse(k, v) != v) return None
dest += e
}
Some(dest.toMap)
}
Here is a fail-slowly solution (if creating the entire map and then discarding it is okay):
def uniqueMap[A,B](s: Seq[(A,B)]) = {
val m = s.toMap
if (m.size == s.length) Some(s) else None
}
Here is a mutable fail-fast solution (bail out as soon as the error is detected):
def uniqueMap[A,B](s: Seq[(A,B)]) = {
val h = new collection.mutable.HashMap[A,B]
val i = s.iterator.takeWhile(x => !(h contains x._1)).foreach(h += _)
if (h.size == s.length) Some(h) else None
}
And here's an immutable fail-fast solution:
def uniqueMap[A,B](s: Seq[(A,B)]) = {
def mapUniquely(i: Iterator[(A,B)], m: Map[A,B]): Option[Map[A,B]] = {
if (i.hasNext) {
val j = i.next
if (m contains j._1) None
else mapUniquely(i, m + j)
}
else Some(m)
}
mapUniquely(s.iterator, Map[A,B]())
}
Edit: and here's a solution using put for speed (hopefully):
def uniqueMap[A,B](s: Seq[(A,B)]) = {
val h = new collection.mutable.HashMap[A,B]
val okay = s.iterator.forall(x => {
val y = (h put (x._1,x._2))
y.isEmpty || y.get == x._2
})
if (okay) Some(h) else None
}
Edit: now tested, and it's ~2x as fast on input that works (returns true) than Moritz' or my straightforward solution.
Scala 2.9 is near, so why not to take advantage of the combinations method (inspired by Moritz's answer):
def optMap[A,B](in: List[(A,B)]) = {
if (in.combinations(2).exists {
case List((a,b),(c,d)) => a == c && b != d
case _ => false
}) None else Some(in.toMap)
}
scala> val in = List(1->1,2->3,3->4,4->5,2->3)
in: List[(Int, Int)] = List((1,1), (2,3), (3,4), (4,5), (2,3))
scala> optMap(in)
res29: Option[scala.collection.immutable.Map[Int,Int]] = Some(Map(1 -> 1, 2 -> 3, 3 -> 4, 4 -> 5))
scala> val in = List(1->1,2->3,3->4,4->5,2->3,1->2)
in: List[(Int, Int)] = List((1,1), (2,3), (3,4), (4,5), (2,3), (1,2))
scala> optMap(in)
res30: Option[scala.collection.immutable.Map[Int,Int]] = None
You can also use gourpBy as follows:
val pList = List(1 -> "a", 1 -> "b", 2 -> "c", 3 -> "d")
def optMap[A,B](in: Iterable[(A,B)]): Option[Map[A,B]] = {
Option(in.groupBy(_._1).map{case(_, list) => if(list.size > 1) return None else list.head})
}
println(optMap(pList))
It's efficiency is competitive to the above solutions.
In fact if you examine the gourpBy implementation you will see that it is very similar to some of the solutions suggested.