I'll give some C-style "bracket" pseudo-code to show what I'd like to express in another way:
for (int i = 0; i < n; i++) {
if (i == 3 || i == 5 || i == 982) {
assertTrue( isCromulent(i) );
} else {
assertFalse( isCromulent(i) );
}
}
The for loop is not very important, that is not the point of my question: I'd like to know how I could rewrite what is inside the loop using Scala.
My goal is not to have the shortest code possible: it's because I'd like to understand what kind of manipulation can be done on method names (?) in Scala.
Can you do something like the following in Scala (following is still some kind of pseudo-code, not Scala code):
assert((i==3 || i==5 || i==982)?True:False)(isCromulent(i))
Or even something like this:
assertTrue( ((i==3 || i==5 || i==982) ? : ! ) isCromulent(i) )
Basically I'd like to know if the result of the test (i==3 || i==5 || i==982) can be used to dispatch between two methods or to add a "not" before an expression.
I don't know if it makes sense so please be kind (look my profile) :)
While pelotom's solution is much better for this case, you can also do this (which is a bit closer to what you asked originally):
(if (i==3||i==5||i==982) assertTrue else assertFalse)(isCromulent(i))
Constructing names dynamically can be done via reflection, but this certainly won't be concise.
assertTrue(isCromulent(i) == (i==3||i==5||i==982))
Within the Scala type system, it isn't possible to dynamically create a method name based on a condition.
But it isn't at all necessary in this case.
val condition = i == 3 || i == 5 || i == 982
assertEquals(condition, isCromulent(i))
I hope nobody minds this response, which is an aside rather than a direct answer.
I found the question and the answers so far very interesting and spent a while looking for a pattern matching based alternative.
The following is an attempt to generalise on this (very specific) category of testing:
class MatchSet(s: Set[Int]) {def unapply(i: Int) = s.contains(i)}
object MatchSet {def apply(s: Int*) = new MatchSet(Set(s:_*))}
val cromulentSet = MatchSet(3, 5, 982)
0 until n foreach {
case i # cromulentSet() => assertTrue(isCromulent(i))
case i => assertFalse(isCromulent(i))
}
The idea is to create ranges of values contained in MatchSet instances rather than use explicit matches.
Related
I'd like to have a generator that terminates, like python, but I can't tell from ranges::views::generate's interface if this is supported.
You can roll it by hand easily enough:
https://godbolt.org/z/xcGz6657r although it's probably better to use a coroutine generator if you have one available.
You can return an optional in the generator, and stop taking elements when a std::nullopt is generated with views::take_while
auto out = ranges::views::generate(
[i = 0]() mutable -> std::optional<int>
{
if (i > 3)
return std::nullopt;
return { i++ };
})
| ranges::views::take_while([](auto opt){ return opt.has_value();})
;
I have a fairly large collection that I would like to iterate and find out if the collection contains more than one instance of a particular number. Since the collection is large, i'd like to exit early, i.e not traverse the complete list.
I have a dirty looking piece of code that does this in a non-functional programming way. However, i'm unable to find a functional programming way of doing this (In Groovy or Scala), since I need to do 2 things at the same time.
Accumulate state
Exit Early
The "accumulate state" can be done using the "inject" or "fold" methods in Groovy/Scala but there's no way of exiting early from those methods. Original groovy code is below. Any thoughts?
def collection = [1,2,3,2,4,6,0,65,... 1 million more numbers]
def n = 2
boolean foundMoreThanOnce(List<Integer> collection, Integer n) {
def foundCount = 0
for(Integer i : collection) {
if(i == n) {
foundCount = foundCount + 1
}
if(foundCount > 1) {
return true
}
}
return false
}
print foundMoreThanOnce(collection, n)
One of many possible Scala solutions.
def foundMoreThanOnce[A](collection: Seq[A], target: A): Boolean =
collection.dropWhile(_ != target).indexOf(target,1) > 0
Or a slight variation...
collection.dropWhile(target.!=).drop(1).contains(target)
Scans the collection only until the 2nd target element is found.
Not sure about groovy, but if possible for you to use Java 8 then there is a possibility
collection.stream().filter(z -> {return z ==2;} ).limit(2)
the limit will stop the stream processing as soon as it get 2nd occurrence of 2.
You can use it as below, to ensure there are exact two occurrences
Long occ = collection.stream().filter(z -> {return z ==2;} ).limit(2).count();
if(occ == 2)
return true;
JavaScript short-circuit evaluation is commonly used to e.g. deal with browser incompatibilities:
var scrollPosition =
window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
What's the idiomatic way to write this in Scala.js?
A contrario #gurghet's answer, IMO the most idiomatic version is to adopt JavaScript's idiom right into Scala.js. After all, you are exploiting the dynamic nature of JavaScript anyway, so you might as well be explicit about it. You can do that with js.Dynamic:
import scala.scalajs.js
import js.Dynamic.{global => g}
def scrollPosition: Double = {
import js.DynamicImplicits._ // to "write JavaScript"
val pos = g.window.pageYOffset || g.document.documentElement.scrollTop || g.document.body.scrollTop || 0
pos.asInstanceOf[Double]
}
I think you are better off thinking in regular scala for this one.
In particular, if you are relying on the cast of 0 to a boolean, this is a bad practice, not per se, but because you rely on implicit casting as rarely as possible and preferably when it does not change the semantic type.
I would rewrite your assignment in a more expressive way
var scrollPosition =
if (window.pageYoffset > 0) {
window.pageYoffset
} else if (document.documentElement.scrollTop > 0) {
document.documentElement.scrollTop
} else if (document.body.scrollTop > 0) {
document.body.scrollTop
} else {
0
}
I can make it even more expressive using a match case or by giving a meaning to
intermediate steps.
I'm refactoring some scala code to teach my coworkers about for-comprehensions, and I've got a line like:
for {
// ...
result <- components.collectFirst({ case section if section.startsWith(DESIRED_SUBSTRING) => section.substring(section.indexOf(DELIM) + 1).trim() == "true" })
} yield result
That's a bit long.
At first, I wished I could just skip the result <- ... followed by the immediate yield, as I can in Haskell, but then I noticed the processing going on inside collectFirst.
So I thought it'd be much easier to read as I should better do this as
for {
// ...
section <- components.filter(_.startsWith(DESIRED_SUBSTRING)).headOption
} yield section.substring(section.indexOf(DELIM) + 1).trim() == "true"
Which works, but it is less efficient, since filter has to process all the elements. I'd like to be able to use a lazy filter:
components.withFilter(_.startsWith(DESIRED_SUBSTRING)).headOption
But FilterMonadic doesn't seem to support headOption, and I can't figure out a way to derive it from the operations it does support. I'm sure there's a way with flatMap and some bf, but I'm too unfamiliar with the scala ecosystem at the moment.
If I want to stick with standard library tricks, am I stuck with
for {
// ...
section <- components.collectFirst({ case section if section.startsWith(DESIRED_SUBSTRING) => section })
} yield section.substring(section.indexOf(DELIM) + 1).trim() == "true"
Or is there something better I can use?
If you use components.find(_.startsWith(DESIRED_SUBSTRING)) that will give you an Option with the first element that meets the condition. Then, you can just map over it with any subsequent processing you need.
for (String stock : allStocks) {
Quote quote = getQuote(...);
if (null == quoteLast) {
continue;
}
Price price = quote.getPrice();
if (null == price) {
continue;
}
}
I don't necessarily need a line by line translation, but I'm looking for the "Scala way" to handle this type of problem.
You don't need continue or breakable or anything like that in cases like this: Options and for comprehensions do the trick very nicely,
val stocksWithPrices =
for {
stock <- allStocks
quote <- Option(getQuote(...))
price <- Option(quote.getPrice())
} yield (stock, quote, price);
Generally you try to avoid those situations to begin with by filtering before you even start:
val goodStocks = allStocks.view.
map(stock => (stock, stock.getQuote)).filter(_._2 != null).
map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null)
(this example showing how you'd carry along partial results if you need them). I've used a view so that results will be computed as-needed, instead of creating a bunch of new collections at each step.
Actually, you'd probably have the quotes and such return options--look around on StackOverflow for examples of how to use those instead of null return values.
But, anyway, if that sort of thing doesn't work so well (e.g. because you are generating too many intermediate results that you need to keep, or you are relying on updating mutable variables and you want to keep the evaluation pattern simple so you know what's happening when) and you can't conceive of the problem in a different, possibly more robust way, then you can
import scala.util.control.Breaks._
for (stock <- allStocks) {
breakable {
val quote = getQuote(...)
if (quoteLast eq null) break;
...
}
}
The breakable construct specifies where breaks should take you to. If you put breakable outside a for loop, it works like a standard Java-style break. If you put it inside, it acts like continue.
Of course, if you have a very small number of conditions, you don't need the continue at all; just use the else of the if-statement.
Your control structure here can be mapped very idiomatically into the following for loop, and your code demonstrates the kind of filtering that Scala's for loop was designed for.
for {stock <- allStocks.view
quote = getQuote(...)
if quoteLast != null
price = quote.getPrice
if null != price
}{
// whatever comes after all of the null tests
}
By the way, Scala will automatically desugar this into the code from Rex Kerr's solution
val goodStocks = allStocks.view.
map(stock => (stock, stock.getQuote)).filter(_._2 != null).
map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null)
This solution probably doesn't work in general for all different kinds of more complex flows that might use continue, but it does address a lot of common ones.
If the focus is really on the continue and not on the null handling, just define an inner method (the null handling part is a different idiom in scala):
def handleStock(stock: String): Unit {
val quote = getQuote(...)
if (null == quoteLast) {
return
}
val price = quote.getPrice();
if (null == price) {
return
}
}
for (stock <- allStocks) {
handleStock(stock)
}
The simplest way is to embed the skipped-over code in an if with reversed-sense to what you have.
See http://www.scala-lang.org/node/257