Scala: Swapping the case of each character in a string - scala

Using Scala I want to take a sub string of an initial string and swap each characters case so that capital letters become lower case lower case become upper.
var swapCase = buffer.substring(lwr, upr).to?OTHER?Case
I have used the .toUpperCase and .toLowerCase commands in the past and was wondering if there is a similar command for just swapping case without having to iterate through each character within a loop and evaluating which operation needs to be performed on each character i.e:
if(char(x).isUpperCase){char(x).toLowerCase}
else if(char(x).isLowerCase){char(x).toUpperCase}
In short, is there a really quick way to do this with a "." command instead of writing multiple lines.

This is about as good as you are going to get:
def swapCase(s: String): String =
s.map(ch => if (ch.isLower) ch.toUpper else ch.toLower)

An alternative to the Tim's oneliner could be:
def swapCharCase(ch: Char) = if (ch.isLower) ch.toUpper else ch.toLower
def swapCase(s: String): String = s.map(swapCharCase)
I find it a tiny bit more readable - and perhaps swapCharCase may become handy anyway.
To use it as .swapCase as requested, use an implicit class instead to provide the extension method:
implicit class CaseStringOps(s: String) {
def swapCase: String = s.map(swapCharCase)
}

Related

I want to make method to replace all occurrences in string with a new variable using recursion

I implemented this method which just replaces all the occurrences of a string (oldVar) with the new string (newVar) in the original String f:
def replace(oldvar: Var, newvar: Var): String =
f.toString.replace(oldvar.toString, newvar.toString)
Works fine, but I'm looking for a recursive approach.
This is a version that works on strings. You should create a custom one that works on Var by delegating to my version after casting Vars to string:
def replace(old: String, neo: String)(f: String): String =
if f.isEmpty then
f
else if f.startsWith(old) then
neo + replace(old, neo)(f.substring(old.length))
else
f.charAt(0).toString + replace(old, neo)(f.substring(1))
Also edge cases such as empty values for old, neo and f should be properly handled by you to avoid "index out of bounds" or infinite recrsion errors.
This is cheating a little, but if you just want recursion ... (not really a fan of solving a straightforward problem in a runaround way "just because").
def replace(s: String, old: String, new_: String): String = s.indexOf(old) match {
case -1 => s
case x => s.substring(0, x) + new_ + replace(s.substring(x + old.length), old, new_)
}
Caveat emptor! This is not a good solution, just the easiest one that satisfies your (quite unreasonable) requirement.
A good one, would at a minimum be (1) tail-recursive and (2) not glue strings together like this (which is rather inefficient). But then, again, we already know that the best solution is to just call .replace, so ... why bother?

(Scala) Creating a data structure for English words

I'm currently working on a problem that involves working with English words. I'm fairly new to functional programming and i want to write as good code as possible. It's a really simple question but i just wanna get this right!^^
How do i create a data structure for English words? I need it because if I ONLY used strings its bad - words can not have any numbers in it or any other inconsistent character - strings allow it.
I'm thinking of making a case class that overrides it's apply(or constructor - I come from OP background so i still mix these up) method that returns Either[String, EnglishWord] where Left would return me an error message - something like - "Found a number in your word". Am i thinking correctly? Any suggestions?
-Thank you so much!!
Cheers=)
You should override the apply method, since you can't make the constructor return anything other than EnglishWord. If you want, you can make the constructor private so that people have to use the apply method.
You can use Try[EnglishWord] instead of Either[String, EnglishWord].
For this sort of thing (wrapping a type in another type for type safety), you may want a value class.
And, of course, make sure you allow corner-case words like "you're", "résumé", "façade", and, as Andrey pointed out, words with digits.
Here is an example:
import scala.util.{ Try, Success, Failure }
case class EnglishWord private(text: String) extends AnyVal
object EnglishWord {
def apply(text: String): Try[EnglishWord] = {
if (isValid(text)) {
Success(new EnglishWord(text))
} else {
Failure(new IllegalArgumentException("Invalid word: " + text))
}
}
def isValid(s: String): Boolean = ???
}

Map an instance using function in Scala

Say I have a local method/function
def withExclamation(string: String) = string + "!"
Is there a way in Scala to transform an instance by supplying this method? Say I want to append an exclamation mark to a string. Something like:
val greeting = "Hello"
val loudGreeting = greeting.applyFunction(withExclamation) //result: "Hello!"
I would like to be able to invoke (local) functions when writing a chain transformation on an instance.
EDIT: Multiple answers show how to program this possibility, so it seems that this feature is not present on an arbitraty class. To me this feature seems incredibly powerful. Consider where in Java I want to execute a number of operations on a String:
appendExclamationMark(" Hello! ".trim().toUpperCase()); //"HELLO!"
The order of operations is not the same as how they read. The last operation, appendExclamationMark is the first word that appears. Currently in Java I would sometimes do:
Function.<String>identity()
.andThen(String::trim)
.andThen(String::toUpperCase)
.andThen(this::appendExclamationMark)
.apply(" Hello "); //"HELLO!"
Which reads better in terms of expressing a chain of operations on an instance, but also contains a lot of noise, and it is not intuitive to have the String instance at the last line. I would want to write:
" Hello "
.applyFunction(String::trim)
.applyFunction(String::toUpperCase)
.applyFunction(this::withExclamation); //"HELLO!"
Obviously the name of the applyFunction function can be anything (shorter please). I thought backwards compatibility was the sole reason Java's Object does not have this.
Is there any technical reason why this was not added on, say, the Any or AnyRef classes?
You can do this with an implicit class which provides a way to extend an existing type with your own methods:
object StringOps {
implicit class RichString(val s: String) extends AnyVal {
def withExclamation: String = s"$s!"
}
def main(args: Array[String]): Unit = {
val m = "hello"
println(m.withExclamation)
}
}
Yields:
hello!
If you want to apply any functions (anonymous, converted from methods, etc.) in this way, you can use a variation on Yuval Itzchakov's answer:
object Combinators {
implicit class Combinators[A](val x: A) {
def applyFunction[B](f: A => B) = f(x)
}
}
A while after asking this question, I noticed that Kotlin has this built in:
inline fun <T, R> T.let(block: (T) -> R): R
Calls the specified function block with this value as its argument and returns
its result.
A lot more, quite useful variations of the above function are provided on all types, like with, also, apply, etc.

folding a list of classes to a single, comma separated string (in Scala)

I have a need to take a list of case classes and convert them to a to a single, comma separated string (with no heading or tailing comma).
case class State(name: String)
def toLine(states: State*): String = {
}
so, toLine(State("one"), State("two"), State("three")) should return one,two,three
here is what I thought of. any better way?
def toLine(states: State*): String = {
states match {
case s if s.isEmpty => throw new Exception
case s => s.tail.foldLeft(s.head.name)(_+","+_)
}
}
is there a way to guaranty there will be at least one value in the list?
You can use mkString:
def toLine(states: State*): String = states.map(_.name).mkString(",")
if you need to ensure at least one element you can do:
def toLine(state: State, states: State*) = (state +: states).map(_.name).mkString(",")
Scala's collections provide a function to do just this: states.map(_.name).mkString(",")
If you want to ensure that toLine is always called with at least one value, you can do this:
def toLine(state: State, states: State*): String = {
states.map(_.name).mkString(",")
}
This will move that check to the type system, rather than doing so at runtime.

Scala right associative methods

I am learning Scala, and playing with right associate unapply object. I know that if the name ends with ':' then it becomes right associative. However, there seems to be some strange restrictions on the naming
e.g.
These are invalid
object cons: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
object :_cons_: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
These are valid
object cons_: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
object >>: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
So there seems to be some weirdness about mixing alpha-numeric characters and symbols in identifiers.
So basically, I want to have a descriptive name i.e. 'cons' and still have right associativity. Also, I would like my operator to be symetric for aesthetic reasons :-), so I dont really like cons_:
Is there a way to make something associate to the right without using a colon? Or any other suggestions to achieve this?
:_cons_: seems to be the closest, but, for some reason the identifier can't start with ':' and have alphanumerics
From the spec (section 1.1):
There are three ways to form an identifier. First, an identifier can
start with a letter which can be followed by an arbitrary sequence of
letters and digits. This may be followed by underscore ‘_’ characters
and another string composed of either letters and digits or of
operator characters. Second, an identifier can start with an operator
character followed by an arbitrary sequence of operator characters.
The preceding two forms are called plain identifiers. Finally, an
identifier may also be formed by an arbitrary string between
back-quotes (host systems may impose some restrictions on which
strings are legal for identifiers). The identifier then is composed of
all characters excluding the backquotes themselves.
So it looks like you're out of luck—if your identifier starts with a : it can't contain non-operator characters. Note, though, that you can write the following (which isn't intended to do anything meaningful—just to demonstrate the syntax):
scala> class X { def `:cons:`(i: Int) = i }
defined class X
scala> val x = new X
x: X = X#6a665da6
scala> 1 `:cons:` x
res1: Int = 1
The method name still ends with a colon, so you get the right associativity you're looking for.