Finding strings which contain the most 'a' letters [closed] - scala

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 1 year ago.
Improve this question
I've got a question if I can somehow shorten my code - I need to find what strings in my List contain the most 'a' letters. I made it as below, but I'm almost sure that I could do it shorter, but I don't know how.
So first of all I map my list to tuple, where I have (el, num) where the num is how many the 'a' contains (using foldLeft).
Then I use maxBy so I take an element that have the most 'a' letters and then I filter all elements where the num == res2._2 (because there could be more than one element having the same number of 'a' letters, so I can't stop at maxBy
My code:
def mostA(l: List[String]): List[String] = {
val res = l.map( string => (string, string.foldLeft(0)((acc,b) => if (b == 'a') acc + 1 else acc)))
val res2 = res.maxBy(x => x._2)
val res3 = res.filter(x => x._2 == res2._2).map{case (str, num) => str}
res3
}

With a bit of an effort, you can do it in one go:
l.foldLeft(List[String] -> 0) { case ((strs, max), s) =>
val n = s.count(_ == letter)
if (n == max) (s::strs, max) else if (n > max) (s::Nil, n) else (strs, max)
}._1.reverse

Your code is already pretty small and concise. However, there is a couple of improvements we can do:
def mostLetter(letter: Char)(data: List[String]): List[String] = {
val counts = data.map(s => s -> s.count(_ == letter))
val max = counts.maxBy(_._2)._2
counts.collect {
case (str, `max`) => str
}
}
Namely, we replaced the foldLeft in the String with count and we fused together the filter + map in a single collect
Also, remember the last expression is the return thus it is unnecessary to assign it to a variable to later just return it.

Related

Reverse Integer in Scala [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I've been trying to figure out a way to reverse an integer in scala (e.g. 1932 -> 2391) without converting to string and in a purely functional way. My goal is to reverse the Int by converting to List then just using List().reverse then converting back to Int.
def reverseIntList(x: Int) : List[Int] = {
if (!(x <= 0))
if ((x > 0) && (x < 10))
x
else
(x % 10) :: reverseIntList(x / 10) :: Nil
else
List()
}
However, I only get this error code:
recursive method reverseIntList needs result type
First unfold() it, then fold() it back up. No .reverse needed.
def reverseInt(x: Int): Int =
List.unfold(x)(n => Option.when(n > 0)((n%10,n/10)))
.fold(0)(_ * 10 + _)
You are returning an Int instead of List[Int] for the first condition.
Also, some enhancement to apply to your code.
No need in this case for the ":: Nil" to construct your list.
No need for "(x > 0)" condition, as it’s already verified by your first if.
It should look like this.
def reverseIntList(x: Int): List[Int] = {
if (!(x <= 0))
if ((x < 10))
List(x)
else
x % 10 :: reverseIntList(x / 10)
else
List()
}

Finding all pairs of two collections that match a predicate using functional style in Scala [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am currently learning Scala and I am looking for good ways to get the most out of functional programming style.
I am trying to do the following:
Given two collections, I want to list every possible combination of two entries that match a predicate.
Now I could solve it using two loops and saving every result in a new collection, but is there a more elegant scala-ey solution?
You can start with
val col1: List[Int]
val col2: List[Int]
col1.map { i =>
col2.map { j =>
(i -> j)
}.filter { case (i, j) =>
// condition
}
}.flatten
map and flatten should be the easiest to understand in the beginning. Play a bit with the idea to look a the types.
Then you might try to replace map(f).flatten with flatMap(f):
col1.flatMap { i =>
col2.map { j =>
(i -> j)
}.filter { case (i, j) =>
// condition
}
}
This is almost identical to this for comprehension:
for {
i <- col1
j <- col2
ij = (i, j)
if condition(ij)
} yield ij
which might be easier to read as
for {
i <- col1
j <- col2
if condition(i, j)
} yield (i, j)
https://scalafiddle.io/sf/mhFZMjt/0

Scala sequence groupBy then map different functions to groups then flatten it [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Generally i has list of elements like that
List(A1, A2, B1, A3, B2, B3, B4, A4, ...)
All elements can be divided by two groups:
A group
B group
For each group i want to applay different functions:
for A: myFunc1
for B: myFunc2
And then collect parts of list into one list.
I gain that by this code:
myList
.groupBy(p => p.sourceId < 0 && p.signerId.isEmpty)
.flatMap(tuple => tuple match {
case tre if tuple._1 =>
tuple
._2
.map(myFunc1)
case fls # _ =>
tuple
._2
.map(myFunc2)
})
But this code looks ugly because each time i need to get value like tuple._2 of any keys (true/false) from Map which i has from groupBy.
What the good and less verbose way of doing that work: divide sequence by 2 groups + map different functions for it + flatten groups to list?
Some variants of answer
by Ethan using map + if/else:
myList.map(p =>
if (p.sourceId < 0 && p.signerId.isEmpty)
myFunc1(p)
else
myFunc2(p)
)
like by Ethan but using match/case instead if/else:
vkPosts.map({
case p1 if p.sourceId < 0 && p.signerId.isEmpty => myFun1(p1)
case pN if p.sourceId > 0 => myFunN(pN)
case pUndefined # _ => myFun2(pUndefined)
})
In this case, you don't actually need to group, you can just have a single map with the if statement in it. Something like
myList.map(p =>
if (p.sourceId < 0 && p.signerId.isEmpty)
myFunc1(p)
else
myFunc2(p)
)
In other cases, you might want to split the collection in two. There's a partition function for that. You can do something like
val (type1, type2) = myList.partition(p => p.sourceId < 0 && p.signerId.isEmpty)
type1.foreach(p => s"Type 1: $p")
type2.foreach(p => s"Type 2: $p")
If you need all the myFunc1() results grouped together and separate from the myFunc2() results.
val (a,b) = myList.partition(p => p.sourceId < 0 && p.signerId.isEmpty)
val rslt = a.map(myFunc1) ++ b.map(myFunc2) //or something like this
If you're on Scala 2.13.x you can pipe them together.
import scala.util.chaining._
myList.partition(p => p.sourceId < 0 && p.signerId.isEmpty)
.pipe(t => t._1.map(myFunc1) ++ t._2.map(myFunc2))

Scala collect function

Let's say I want to print duplicates in a list with their count. So I have 3 options as shown below:
def dups(dup:List[Int]) = {
//1)
println(dup.groupBy(identity).collect { case (x,ys) if ys.lengthCompare(1) > 0 => (x,ys.size) }.toSeq)
//2)
println(dup.groupBy(identity).collect { case (x, List(_, _, _*)) => x }.map(x => (x, dup.count(y => x == y))))
//3)
println(dup.distinct.map((a:Int) => (a, dup.count((b:Int) => a == b )) ).filter( (pair: (Int,Int) ) => { pair._2 > 1 } ))
}
Questions:
-> For option 2, is there any way to name the list parameter so that it can be used to append the size of the list just like I did in option 1 using ys.size?
-> For option 1, is there any way to avoid the last call to toSeq to return a List?
-> which one of the 3 choices is more efficient by using the least amount of loops?
As an example input: List(1,1,1,2,3,4,5,5,6,100,101,101,102)
Should print: List((1,3), (5,2), (101,2))
Based on #lutzh answer below the best way would be to do the following:
val list: List[(Int, Int)] = dup.groupBy(identity).collect({ case (x, ys # List(_, _, _*)) => (x, ys.size) })(breakOut)
val list2: List[(Int, Int)] = dup.groupBy(identity).collect { case (x, ys) if ys.lengthCompare(1) > 0 => (x, ys.size) }(breakOut)
For option 1 is there any way to avoid the last call to toSeq to
return a List?
collect takes a CanBuildFrom, so if you assign it to something of the desired type you can use breakOut:
import collection.breakOut
val dups: List[(Int,Int)] =
dup
.groupBy(identity)
.collect({ case (x,ys) if ys.size > 1 => (x,ys.size)} )(breakOut)
collect will create a new collection (just like map), using a Builder. Usually the return type is determined by the origin type. With breakOut you basically ignore the origin type and look for a builder for the result type. So when collect creates the resulting collection, it will already create the "right" type, and you don't have to traverse the result again to convert it.
For option 2, is there any way to name the list parameter so that it
can be used to append the size of the list just like I did in option 1
using ys.size?
Yes, you can bind it to a variable with #
val dups: List[(Int,Int)] =
dup
.groupBy(identity)
.collect({ case (x, ys # List(_, _, _*)) => (x, ys.size) } )(breakOut)
which one of the 3 choices is more efficient?
Calling dup.count on a match seems inefficient, as dup needs to be traversed again then, I'd avoid that.
My guess would be that the guard (if lengthCompare(1) > 0) takes a few cycles less than the List(,,_*) pattern, but I haven't measured. And am not planning to.
Disclaimer: There may be a completely different (and more efficient) way of doing it that I can't think of right now. I'm only answering your specific questions.

How do you pad a string in Scala with a character for missing elements in a Vector?

If I have a sparse list of numbers:
Vector(1,3,7,8,9)
and I need to generate a string of a fixed size which replaces the 'missing' numbers with a given character that might look like this:
1.3...789
How would I do this in Scala?
Well, I'm not sure the range of the integers. So I'm assuming that they may not fit into a char and used a string. Try this:
val v = Vector(1,3,7,8,9)
val fixedStr = ( v.head to v.last )
.map( i => if (v.contains(i)) i.toString else "." )
.mkString
If you are only dealing with single digits then you may change the strings to chars in the above.
-- edit --
ok, so I couldn't help myself and addressed the issue of sparse vector and wanted to change it to use the sliding function. Figured it does no good sitting on my PC so sharing here:
v.sliding(2)
.map( (seq) => if (seq.size == 2) seq else seq ++ seq ) //normalize window to size 2
.foldLeft( new StringBuilder )( (sb, seq) => //fold into stringbuilder
seq match { case Seq(a,b) => sb.append(a).append( "." * (b - a - 1) ) } )
.append( v.last )
.toString
One way to do this is using sliding and pattern matching:
def mkNiceString(v: Vector[Int]) = {
v.sliding(2).map{
case Seq(a) => ""
case Seq(a,b) =>
val gap = b-a;
a.toString + (if(gap>1) "." * (gap-1) else "")
}.mkString + v.last
}
In the REPL:
scala> mkNiceString(Vector(1,3,7,8,9,11))
res22: String = 1.3...789.11
If the vector is sparse, this will be more efficient than checking the range between the first and the last number.
def padVector(numbers: Vector[Int], placeHolder: String) = {
def inner(nums: Vector[Int], prevNumber: Int, acc: String) : String =
if (nums.length == 0) acc
else (nums.head - prevNumber) match {
// the difference is 1 -> no gap between this and previous number
case 1 => inner(nums.tail, nums.head, acc + nums.head)
// gap between numbers -> add placeholder x times
case x => inner(nums.tail, nums.head, acc + (placeHolder * (x-1)) + nums.head)
}
if (numbers.length == 0) ""
else inner(numbers.tail, numbers.head, numbers.head.toString)
}
Output:
scala> padVector(Vector(1,3,7,8,9), ".")
res4: String = 1.3...789