I have a file like this:
1 4.146846
2 3.201141
3 3.016736
4 2.729412
I want to use toDouble but, it's not working as expected :
val rows = textFile.map { line =>
val fields = line.split("[^\\d]+")
((fields(0),fields(1).toDouble))
}
val Num = rows.sortBy(- _._2).map{case (user , num) => num}.collect.mkString("::")
println(Num)
The result print out is 4.0::3.0::3.0::2.0.
What I expect is 4.146846::3.201141::3.016736::2.729412
How do I do this?
Your regular expression is stopping at the decimal point in 4.146846.
Try line.split("[^\\d.]+")
What about splitting the lines by variant number of whitespaces? The regular expression would be like '[\s]+' . This resumes in two parts per line, one digit and one double string.
My whole program looks like:
object Application {
def parseDouble(s: String) =
try {
Some(s.toDouble)
} catch {
case _ => None
}
def main(args: Array[String]): Unit = {
val linesIt = "1 3.201141\n2 4.146846\n3 3.016736\n4 2.729412".lines
var doubles: List[Double] = List.empty
for (singleLine <- linesIt) {
val oneDouble = parseDouble(singleLine.split("[\\s]+")(1))
doubles = if (oneDouble != None)
oneDouble.get::doubles
else
doubles
}
val doublesArr = doubles.toArray
println("before sorting: " + doublesArr.mkString("::"))
scala.util.Sorting.quickSort(doublesArr)
println("after sorting: " + doublesArr.mkString("::"))
}
}
Related
Apologies , but am new to scala... learning it, now.
I have been trying to complete a excercise where the ask was as follows :-
// Write a function isPerfectNumber which takes integer input and returns String output.
// It finds if a number is perfect, and returns true if perfect, else returns false
// Write a higher order function myHigherOrderFunction which takes isPerfectNumber and intList as input, and returns a List of Strings which contain the output if the number is perfect or not using map.
Perfect Number :
https://rosettacode.org/wiki/Perfect_numbers
just go to the scala section
My Code :
object ListMapHigherOrder{
def main(args:Array[String])
{
val intRes = args.toList
val intList: List[Int] = intRes.map(_.toInt).toList
def isPerfectNumber(input: Int) :String =
{
var check_sum = ( (2 to math.sqrt(input).toInt).collect { case x if input % x == 0 => x + input / x} ).sum
if ( check_sum == input - 1 )
return "true"
else
return "false"
}
def myHigherOrderFunction(argFn: Int => String, argVal:List[Int]): List[String] = { argVal.map(argFn) }
println(myHigherOrderFunction(isPerfectNumber, intList))
}
}
Code execution : scala ScalaExcercise12.scala 1 6 13
Expected Output : List(false , true , false)
the code gives expected output, am not sure how the backend testing is being done.... it just dosent pass the test.
Is there any issue with the code? - i did like to fix it , but cant i see anything wrong/missing especially because i am getting the same output as desired :(
object ListMapHigherOrder{
def main(args:Array[String])
{
val intRes = args.toList
val intList: List[Int] = intRes.map(x=>x.toInt)
def isPerfectNumber(input: Int) :String =
{
var sum = 0
for(i <- 1 until input){
if(input % i == 0)
sum = sum+i
}
if ( sum == input )
return "true"
else
return "false"
}
def myHigherOrderFunction(argFn: Int => String, argVal:List[Int]): List[String] = { argVal.map(argFn) }
println(myHigherOrderFunction(isPerfectNumber, intList))
}
}
**This worked for me
How can I shorten the following piece of code (the toText method) with higher level methods like map, takeWhile, filter, etc.:
/** Returns the text that is produced by this keypad from the given multi-tap input.
* For instance, the input `"33 3338881330000"` produces `"HIYAH!"`. The given string
* is assumed to consist of digits and spaces only.
*/
def toText(keysPressed: String): String = {
val pieces = keysPressed.split(" ")
var result = "" // gatherer
for (currentPiece <- pieces) { // most-recent holder
var remaining = currentPiece // gatherer
while (remaining.nonEmpty) {
val copyCount = countInitialCopies(remaining) // temporary
result += charFor(remaining(0), copyCount)
remaining = remaining.drop(copyCount)
}
}
result
}
where:
/** Returns the character produced by pressing the given number key (from '0' to '9')
* the given number of times on this keypad. If a key is pressed more times than there
* are characters assigned to the key, the result "wraps around".
*/
def charFor(keyPressed: Char, timesPressed: Int): Char = {
val charactersForKeys = Vector(" .,!?", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ", "ÅÄÖ")
val key = charactersForKeys(keyPressed.asDigit)
key((timesPressed-1) % key.length)
}
and:
/** Determines the first letter of the given string, and returns the number of times
* the letter occurs consecutively at the beginning of the string. The given
* string must have at least one character.
*/
def countInitialCopies(str: String): Int = str.takeWhile(_ == str(0)).length
I tried to do the following, but it didn't go that far:
def toText(keysPressed: String): String = keysPressed.split(" ").foldLeft("")(charFor(_(0), countInitialCopies(_)))
Here's a slightly different approach to the problem. Uses takeWhile() but not much else.
val charsForKeys = Vector(" .,!?", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ")
def toText(keysPressed: String): String = {
if (keysPressed.isEmpty) ""
else {
val kpHead = keysPressed.head
val kpStr = keysPressed.takeWhile(_ == kpHead)
val kpLen = kpStr.length
if (kpHead.isDigit)
charsForKeys(kpHead.asDigit)(kpLen-1) + toText(keysPressed.drop(kpLen))
else
toText(keysPressed.drop(kpLen)) //not a digit, skip these chars
}
}
toText("33 3338881330000") //res0: String = HIYAH!
2nd, shorter, attempt. Uses foldRight() and collect().
def toText(keysPressed: String): String = {
keysPressed.foldRight(List[String]()){
case (c, s::ss) => if (c == s.head) c+s :: ss
else c.toString :: s :: ss
case (c, Nil) => List(c.toString)
}.collect{
case s if s.head.isDigit => charsForKeys(s.head.asDigit)(s.length-1)
}.mkString
}
Not sure if it is really shorter but here is one:
def toText(keysPressed: String): String = {
def split(seq: Seq[Char]): Stream[Seq[Char]] = {
if (seq.isEmpty)
Stream.empty
else {
val lr = seq.span(ch => ch == seq.head)
Stream.cons(lr._1, split(lr._2))
}
}
split(keysPressed)
.filter(s => s.head.isDigit) // filter out spaces between different series of the same digits
.map(s => charFor(s.head, s.length))
.mkString("")
}
The idea behind this code is:
first split the keysPressed (treated as Seq[Char] thanks to implicit scala.collection.immutable.StringOps) into a Stream[Seq[Char]] in a way similar to your countInitialCopies (note that cons second argument is a "recursive" (actually delayed) call on the rest of the Seq!)
then filter out Seq[Char] that come from spaces for explicit groups separation,
then map that filtered Stream[Seq[Char]] using your charFor
finally accumulate the result from Stream into a String
I have the following string that I would like to match on: 1-10 employees.
Here is my regex statement val regex = ("\\d+").r
The problem I have is Im trying to find a way to extract the matched data and determine which value returned is bigger.
Here is what IM doing to process it
def setMinAndMaxValue(currentCompany: CurrentCompany, matchIterator: Iterator[Regex.Match]): CurrentCompany = {
var max = 0
println(s"matchIterator - $matchIterator")
matchIterator.collect {
case regex(s: String) => println("found string")
case regex(IntConv(x)) =>
println("regex case")
if (x > max) max = x
}
val (minVal, maxVal) = rangesForMaxValue(max)
val newDetails = currentCompany.details.copy(minSize = Some(minVal), maxSize = Some(maxVal))
currentCompany.copy(details = newDetails)
}
object IntConv {
def unapply(s : String) : Option[Int] = Try {
Some(s.toInt)
}.toOption.flatten
}
I thought I was confused by your original question, then you clarified it with code and now I have no idea what you're trying to do.
To extract numbers from a string, try this.
val re = """(\d+)""".r
val nums = re.findAllIn(string_with_numbers).map(_.toInt).toList
Then you can just nums.min, and nums.max, and whatever number processing you need.
I am reading a TSV file and using using something like this:
case class Entry(entryType: Int, value: Int)
def filterEntries(): Iterator[Entry] = {
for {
line <- scala.io.Source.fromFile("filename").getLines()
} yield new Entry(line.split("\t").map(x => x.toInt))
}
Now I am both interested in filtering out entries whose entryType are set to 0 and ignoring lines with column count greater or lesser than 2 (that does not match the constructor). I was wondering if there's an idiomatic way to achieve this may be using pattern matching and unapply method in a companion object. The only thing I can think of is using .filter on the resulting iterator.
I will also accept solution not involving for loop but that returns Iterator[Entry]. They solutions must be tolerant to malformed inputs.
This is more state-of-arty:
package object liner {
implicit class R(val sc: StringContext) {
object r {
def unapplySeq(s: String): Option[Seq[String]] = sc.parts.mkString.r unapplySeq s
}
}
}
package liner {
case class Entry(entryType: Int, value: Int)
object I {
def unapply(s: String): Option[Int] = util.Try(s.toInt).toOption
}
object Test extends App {
def lines = List("1 2", "3", "", " 4 5 ", "junk", "0, 100000", "6 7 8")
def entries = lines flatMap {
case r"""\s*${I(i)}(\d+)\s+${I(j)}(\d+)\s*""" if i != 0 => Some(Entry(i, j))
case __________________________________________________ => None
}
Console println entries
}
}
Hopefully, the regex interpolator will make it into the standard distro soon, but this shows how easy it is to rig up. Also hopefully, a scanf-style interpolator will allow easy extraction with case f"$i%d".
I just started using the "elongated wildcard" in patterns to align the arrows.
There is a pupal or maybe larval regex macro:
https://github.com/som-snytt/regextractor
You can create variables in the head of the for-comprehension and then use a guard:
edit: ensure length of array
for {
line <- scala.io.Source.fromFile("filename").getLines()
arr = line.split("\t").map(x => x.toInt)
if arr.size == 2 && arr(0) != 0
} yield new Entry(arr(0), arr(1))
I have solved it using the following code:
import scala.util.{Try, Success}
val lines = List(
"1\t2",
"1\t",
"2",
"hello",
"1\t3"
)
case class Entry(val entryType: Int, val value: Int)
object Entry {
def unapply(line: String) = {
line.split("\t").map(x => Try(x.toInt)) match {
case Array(Success(entryType: Int), Success(value: Int)) => Some(Entry(entryType, value))
case _ =>
println("Malformed line: " + line)
None
}
}
}
for {
line <- lines
entryOption = Entry.unapply(line)
if entryOption.isDefined
} yield entryOption.get
The left hand side of a <- or = in a for-loop may be a fully-fledged pattern. So you may write this:
def filterEntries(): Iterator[Int] = for {
line <- scala.io.Source.fromFile("filename").getLines()
arr = line.split("\t").map(x => x.toInt)
if arr.size == 2
// now you may use pattern matching to extract the array
Array(entryType, value) = arr
if entryType == 0
} yield Entry(entryType, value)
Note that this solution will throw a NumberFormatException if a field is not convertible to an Int. If you do not want that, you'll have to encapsulate x.toInt with a Try and pattern match again.
I was wondering if there is any way of preserving indentation while doing string interpolation in scala. Essentially, I was wondering if I could interpose my own StringContext. Macros would address this problem, but I'd like to wait until they are official.
This is what I want:
val x = "line1 \nline2"
val str = s"> ${x}"
str should evaluate to
> line1
line2
Answering my question, and converting Daniel Sobral's very helpful answer to code. Hopefully it will be of use to someone else with the same issue. I have not used implicit classes since I am still pre-2.10.
Usage:
import Indenter._ and use string interpolation like so e" $foo "
Example
import Indenter._
object Ex extends App {
override def main(args: Array[String]) {
val name = "Foo"
val fields = "x: Int\ny:String\nz:Double"
// fields has several lines. All of them will be indented by the same amount.
print (e"""
class $name {
${fields}
}
""")
}
}
should print
class Foo
x: Int
y: String
z: Double
Here's the custom indenting context.
class IndentStringContext(sc: StringContext) {
def e(args: Any*):String = {
val sb = new StringBuilder()
for ((s, a) <- sc.parts zip args) {
sb append s
val ind = getindent(s)
if (ind.size > 0) {
sb append a.toString().replaceAll("\n", "\n" + ind)
} else {
sb append a.toString()
}
}
if (sc.parts.size > args.size)
sb append sc.parts.last
sb.toString()
}
// get white indent after the last new line, if any
def getindent(str: String): String = {
val lastnl = str.lastIndexOf("\n")
if (lastnl == -1) ""
else {
val ind = str.substring(lastnl + 1)
if (ind.trim.isEmpty) ind // ind is all whitespace. Use this
else ""
}
}
}
object Indenter {
// top level implicit defs allowed only in 2.10 and above
implicit def toISC(sc: StringContext) = new IndentStringContext(sc)
}
You can write your own interpolators, and you can shadow the standard interpolators with your own. Now, I have no idea what's the semantic behind your example, so I'm not even going to try.
Check out my presentation on Scala 2.10 on either Slideshare or SpeakerDeck, as they contain examples on all the manners in which you can write/override interpolators. Starts on slide 40 (for now -- the presentation might be updated until 2.10 is finally out).
For Anybody seeking a post 2.10 answer:
object Interpolators {
implicit class Regex(sc: StringContext) {
def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
}
implicit class IndentHelper(val sc: StringContext) extends AnyVal {
import sc._
def process = StringContext.treatEscapes _
def ind(args: Any*): String = {
checkLengths(args)
parts.zipAll(args, "", "").foldLeft("") {
case (a, (part, arg)) =>
val processed = process(part)
val prefix = processed.split("\n").last match {
case r"""([\s|]+)$d.*""" => d
case _ => ""
}
val argLn = arg.toString
.split("\n")
val len = argLn.length
// Todo: Fix newline bugs
val indented = argLn.zipWithIndex.map {
case (s, i) =>
val res = if (i < 1) { s } else { prefix + s }
if (i == len - 1) { res } else { res + "\n" }
}.mkString
a + processed + indented
}
}
}
}
Here's a short solution. Full code and tests on Scastie. There are two versions there, a plain indented interpolator, but also a slightly more complex indentedWithStripMargin interpolator which allows it to be a bit more readable:
assert(indentedWithStripMargin"""abc
|123456${"foo\nbar"}-${"Line1\nLine2"}""" == s"""|abc
|123456foo
| bar-Line1
| Line2""".stripMargin)
Here is the core function:
def indentedHelper(parts: List[String], args: List[String]): String = {
// In string interpolation, there is always one more string than argument
assert(parts.size == 1+args.size)
(parts, args) match {
// The simple case is where there is one part (and therefore zero args). In that case,
// we just return the string as-is:
case (part0 :: Nil, Nil) => part0
// If there is more than one part, we can simply take the first two parts and the first arg,
// merge them together into one part, and then use recursion. In other words, we rewrite
// indented"A ${10/10} B ${2} C ${3} D ${4} E"
// as
// indented"A 1 B ${2} C ${3} D ${4} E"
// and then we can rely on recursion to rewrite that further as:
// indented"A 1 B 2 C ${3} D ${4} E"
// then:
// indented"A 1 B 2 C 3 D ${4} E"
// then:
// indented"A 1 B 2 C 3 D 4 E"
case (part0 :: part1 :: tailparts, arg0 :: tailargs) => {
// If 'arg0' has newlines in it, we will need to insert spaces. To decide how many spaces,
// we count many characters after after the last newline in 'part0'. If there is no
// newline, then we just take the length of 'part0':
val i = part0.reverse.indexOf('\n')
val n = if (i == -1)
part0.size // if no newlines in part0, we just take its length
else
i // the number of characters after the last newline
// After every newline in arg0, we must insert 'n' spaces:
val arg0WithPadding = arg0.replaceAll("\n", "\n" + " "*n)
val mergeTwoPartsAndOneArg = part0 + arg0WithPadding + part1
// recurse:
indentedHelper(mergeTwoPartsAndOneArg :: tailparts, tailargs)
}
// The two cases above are exhaustive, but the compiler thinks otherwise, hence we need
// to add this dummy.
case _ => ???
}
}