Scala check if element is present in a list - string

I need to check if a string is present in a list, and call a function which accepts a boolean accordingly.
Is it possible to achieve this with a one liner?
The code below is the best I could get:
val strings = List("a", "b", "c")
val myString = "a"
strings.find(x=>x == myString) match {
case Some(_) => myFunction(true)
case None => myFunction(false)
}
I'm sure it's possible to do this with less coding, but I don't know how!

Just use contains
myFunction(strings.contains(myString))

And if you didn't want to use strict equality, you could use exists:
myFunction(strings.exists { x => customPredicate(x) })

Even easier!
strings contains myString

this should work also with different predicate
myFunction(strings.find( _ == mystring ).isDefined)

In your case I would consider using Set and not List, to ensure you have unique values only. unless you need sometimes to include duplicates.
In this case, you don't need to add any wrapper functions around lists.

You can also implement a contains method with foldLeft, it's pretty awesome. I just love foldLeft algorithms.
For example:
object ContainsWithFoldLeft extends App {
val list = (0 to 10).toList
println(contains(list, 10)) //true
println(contains(list, 11)) //false
def contains[A](list: List[A], item: A): Boolean = {
list.foldLeft(false)((r, c) => c.equals(item) || r)
}
}

Related

For comprehension parsing of optional string to int

Say I have the following for comprehension:
val validatedInput = for {
stringID <- parseToInt(optionalInputID)
} yield (stringID)
where optionalInputID is an input parameter of type Option[String]. I want to be able to convert an Option[String] into just a String, if of course there is an option present. As far as I'm aware, you cannot case match inside a for comprehension.
Some details have been omitted, such as other for comprehension items. Therefore I would like to know if it's possible to do this inside the for comprehension. If not, then what's a suitable alternative? Can I do it outside of the for comprehension?
Simply add it to the for comprehension:
val validatedInput = for {
inputID <- optionalInputID
stringID <- parseToInt(inputID)
} yield (stringID)
It will work only if parseToInt has type of Option. If it returns something of Try, you can't do it - because you can't mix Try and Option in the same for-comprehension.
If parseToInt returns Try, you can do the following:
val validatedInput = for {
inputID <- optionalInputID
stringID <- parseToInt(inputID).toOption
} yield (stringID)
I want to be able to convert an Option[String] into just a String.
Therefore I would like to know if it's possible to do this inside the for comprehension
In Scala, for-comprehension desugars into a combinitation of map, flatMap, filter, none of which allows to extract the value out of the Option.
If not, then what's a suitable alternative? Can I do it outside of the for comprehension?
To do so you can use one of get (unsafe), or it safer version getOrElse, or fold:
val validatedInput: Option[String] = Some("myString")
scala>validatedInput.get
// res1: String = "myString"
scala>validatedInput.getOrElse("empty")
// res2: String = "myString"
scala>validatedInput.fold("empty")(identity)
// res3: String = "myString"

Short-circuiting in functional Groovy?

"When you've found the treasure, stop digging!"
I'm wanting to use more functional programming in Groovy, and thought rewriting the following method would be good training. It's harder than it looks because Groovy doesn't appear to build short-circuiting into its more functional features.
Here's an imperative function to do the job:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
String shortestUniqueName(String nameToShorten) {
def currentLevel = 1
String shortName = ''
def separator = '/'
while (fullyQualifiedNames.findAll { fqName ->
shortName = nameToShorten.tokenize(separator)[-currentLevel..-1].join(separator)
fqName.endsWith(shortName)
}.size() > 1) {
++currentLevel
}
return shortName
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
It scans a list of fully-qualified filenames and returns the shortest unique form. There are potentially hundreds of fully-qualified names.
As soon as the method finds a short name with only one match, that short name is the right answer, and the iteration can stop. There's no need to scan the rest of the name or do any more expensive list searches.
But turning to a more functional flow in Groovy, neither return nor break can drop you out of the iteration:
return simply returns from the present iteration, not from the whole .each so it doesn't short-circuit.
break isn't allowed outside of a loop, and .each {} and .eachWithIndex {} are not considered loop constructs.
I can't use .find() instead of .findAll() because my program logic requires that I scan all elements of the list, nut just stop at the first.
There are plenty of reasons not to use try..catch blocks, but the best I've read is from here:
Exceptions are basically non-local goto statements with all the
consequences of the latter. Using exceptions for flow control
violates the principle of least astonishment, make programs hard to read
(remember that programs are written for programmers first).
Some of the usual ways around this problem are detailed here including a solution based on a new flavour of .each. This is the closest to a solution I've found so far, but I need to use .eachWithIndex() for my use case (in progress.)
Here's my own poor attempt at a short-circuiting functional solution:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
def shortestUniqueName(String nameToShorten) {
def found = ''
def final separator = '/'
def nameComponents = nameToShorten.tokenize(separator).reverse()
nameComponents.eachWithIndex { String _, int i ->
if (!found) {
def candidate = nameComponents[0..i].reverse().join(separator)
def matches = fullyQualifiedNames.findAll { String fqName ->
fqName.endsWith candidate
}
if (matches.size() == 1) {
found = candidate
}
}
}
return found
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
Please shoot me down if there is a more idiomatic way to short-circuit in Groovy that I haven't thought of. Thank you!
There's probably a cleaner looking (and easier to read) solution, but you can do this sort of thing:
String shortestUniqueName(String nameToShorten) {
// Split the name to shorten, and make a list of all sequential combinations of elements
nameToShorten.split('/').reverse().inject([]) { agg, l ->
if(agg) agg + [agg[-1] + l] else agg << [l]
}
// Starting with the smallest element
.find { elements ->
fullyQualifiedNames.findAll { name ->
name.endsWith(elements.reverse().join('/'))
}.size() == 1
}
?.reverse()
?.join('/')
?: ''
}

takeRightWhile() method in scala

I might be missing something but recently I came across a task to get last symbols according to some condition. For example I have a string: "this_is_separated_values_5". Now I want to extract 5 as Int.
Note: number of parts separated by _ is not defined.
If I would have a method takeRightWhile(f: Char => Boolean) on a string it would be trivial: takeRightWhile(ch => ch != '_'). Moreover it would be efficient: a straightforward implementation would actually involve finding the last index of _ and taking a substring while the use of this method would save first step and provide better average time complexity.
UPDATE: Guys, all the variations of str.reverse.takeWhile(_!='_').reverse are quite inefficient as you actually use additional O(n) space. If you want to implement method takeRightWhile efficiently you could iterate starting from the right, accumulating result in string builder of whatever else, and returning the result. I am asking about this kind of method, not implementation which was already described and declined in the question itself.
Question: Does this kind of method exist in scala standard library? If no, is there method combination from the standard library to achieve the same in minimum amount of lines?
Thanks in advance.
Possible solution:
str.reverse.takeWhile(_!='_').reverse
Update
You can go from right to left with following expression using foldRight:
str.toList.foldRight(List.empty[Char]) {
case (item, acc) => item::acc
}
Here you need to check condition and stop adding items after condition met. For this you can pass a flag to accumulated value:
val (_, list) = str.toList.foldRight((false, List.empty[Char])) {
case (item, (false, list)) if item!='_' => (false, item::list)
case (_, (_, list)) => (true, list)
}
val res = list.mkString.toInt
This solution is even more inefficient then solution with double reverse:
Implementation of foldRight uses combination of List reverse and foldLeft
You cannot break foldRight execution, so you need flag to skip all items after condition met
I'd go with this:
val s = "string_with_following_number_42"
s.split("_").reverse.head
// res:String = 42
This is a naive attempt and by no means optimized. What it does is splitting the String into an Array of Strings, reverses it and takes the first element. Note that, because the reversing happens after the splitting, the order of the characters is correct.
I am not exactly sure about the problem you are facing. My understanding is that you want have a string of format xxx_xxx_xx_...._xxx_123 and you want to extract the part at the end as Int.
import scala.util.Try
val yourStr = "xxx_xxx_xxx_xx...x_xxxxx_123"
val yourInt = yourStr.split('_').last.toInt
// But remember that the above is unsafe so you may want to take it as Option
val yourIntOpt = Try(yourStr.split('_').last.toInt).toOption
Or... lets say your requirement is to collect a right-suffix till some boolean condition remains true.
import scala.util.Try
val yourStr = "xxx_xxx_xxx_xx...x_xxxxx_123"
val rightSuffix = yourStr.reverse.takeWhile(c => c != '_').reverse
val yourInt = rightSuffix.toInt
// but above is unsafe so
val yourIntOpt = Try(righSuffix.toInt).toOption
Comment if your requirement is different from this.
You can use StringBuilder and lastIndexWhere.
val str = "this_is_separated_values_5"
val sb = new StringBuilder(str)
val lastIdx = sb.lastIndexWhere(ch => ch != '_')
val lastCh = str.charAt(lastIdx)

Scala strings - how to change lines

I'm trying to create an informative report according to results.
I currently have a .foreach loop iterating over a list, and writes the report.
The code looks like:
result.foreach {
tupleResult =>
tupleResult._3 match {
case "FirstTest" =>
language1 = createReport(tupleResult)
case "SecondTest" =>
language2 = createReport(tupleResult)
case "ThirdTest" =>
language3 = createReport(tupleResult)
}
finalReport = ""
}
Each "createReport" is a method which creates a one line String into the relevant language var.
I want each iteration to add a different line in the "finalReport" string.
Example of "finalReport":
Report consists of the following:
1) language1
2) language2
3) language3
The question is how to create the different variables as different lines of the same "finalReport" string.
The more idiomatic scala way to do it would be to not do several things at once and also mutate state, but instead see it as separate operations/expressions. Something like this for example:
val sortedResults = result.sortBy(_._3 match {
case "FirstTest" => 1
case "SecondTest" => 2
case "ThirdTest" => 3
})
val reportLines = sortedResults.map(result => createReport(result._3))
val finalReport = reportLines.mkString("\n")
Associating an ordering to the test strings may prove a solution, for instance like this,
val ord = Array("FirstTest","SecondTest","ThirdTest").zipWithIndex.toMap
Then we can generate the parts of the report, and finally sort them by the defined ordering,
val finalReport = result.map { tRes => (ord.get(tRes._3), createReport(tRes)) }
.sortBy(_._1)
.map(_._2)
.mkString("\n")

String method to change particular element in Scala

I need to write a method in Scala that overrides the toString method. I wrote it but I also have to check that if there is an element that is '1' I will change it to 'a', else write the list as it is with the string method. Any suggestions how this can be done?
What error are you getting? seems to work for me
val l = List(1, 2, 3)
println(this)
override def toString(): String = {
val t = l.map({
case 1 => "a"
case x => x
})
t.toString
}
getting List(a, 2, 3) printed out
I see from the comments on your question that list is a List[List[Int]].
Look at the beginning of your code:
list.map { case 1 => 'a'; case x => x}
map expects a function that takes an element of list as a parameter - a List[Int], in your case. But your code works directly on Int.
With this information, it appears that the error you get is entirely correct: you declared a method that expects an Int, but you pass a List[Int] to it, which is indeed a type mismatch.
Try this:
list.map {_.map { case 1 => 'a'; case x => x}}
This way, the function you defined to transform 1 to a and leave everything else alone is applied to list's sublists, and this type-checks: you're applying a function that expects an Int to an Int.

Resources