I'm trying out ScalaCheck and haven't been able to figure out how to build the first example on the ScalaTest user's manual. I'm pretty sure that the following needs to be preceded by some imports and wrapped inside a class that extends from some library class. The page in the user's manual says to "mix in" PropertyChecks, but it doesn't give an example of an appropriate class to mix it into:
forAll { (n: Int, d: Int) =>
whenever (d != 0 && d != Integer.MIN_VALUE
&& n != Integer.MIN_VALUE) {
val f = new Fraction(n, d)
if (n < 0 && d < 0 || n > 0 && d > 0)
f.numer should be > 0
else if (n != 0)
f.numer should be < 0
else
f.numer should be === 0
f.denom should be > 0
}
}
I've been trying various combinations, but the best result I've gotten so far is compilation errors like this:
[info] Compiling 1 Scala source to .../target/scala-2.11/test-classes...
[error] .../src/test/scala/TestFraction.scala:14: value should is not a member of Int
[error] f.numer should be > 0
[error] ^
What would be a complete source file for the test, imports and all?
If you check the github repository of scala test here you can find some extra code here
github source scalatest
For your source this are the imports and the structure
import org.scalatest.{Matchers, FlatSpec}
import org.scalatest.prop.PropertyChecks
class Fraction(n: Int, d: Int) {
require(d != 0)
require(d != Integer.MIN_VALUE)
require(n != Integer.MIN_VALUE)
val numer = if (d < 0) -1 * n else n
val denom = d.abs
override def toString = numer + " / " + denom
}
class PropertySpec extends FlatSpec with PropertyChecks with Matchers {
forAll { (n: Int, d: Int) =>
whenever(d != 0 && d != Integer.MIN_VALUE
&& n != Integer.MIN_VALUE) {
val f = new Fraction(n, d)
if (n < 0 && d < 0 || n > 0 && d > 0)
f.numer should be > 0
else if (n != 0)
f.numer should be < 0
else
f.numer should be === 0
f.denom should be > 0
}
}
val invalidCombos =
Table(
("n", "d"),
(Integer.MIN_VALUE, Integer.MIN_VALUE),
(1, Integer.MIN_VALUE),
(Integer.MIN_VALUE, 1),
(Integer.MIN_VALUE, 0),
(1, 0)
)
forAll(invalidCombos) { (n: Int, d: Int) =>
evaluating {
new Fraction(n, d)
} should produce[IllegalArgumentException]
}
}
Recent versions of scalatest do not implementevaluating and mark === as obsolete.
So, I'd rewrite example as:
import org.scalatest._
import org.scalatest.prop.PropertyChecks
protected class Fraction(n: Int, d: Int) {
require(d != 0 && d != Integer.MIN_VALUE && n != Integer.MIN_VALUE)
val numer = if (d < 0) -1 * n else n
val denom = d.abs
override def toString = numer + " / " + denom
}
class SscceProps extends FlatSpec with PropertyChecks with Matchers {
it should "valid combos" in { forAll { (n: Int, d: Int) =>
whenever(d != 0 && d != Integer.MIN_VALUE && n != Integer.MIN_VALUE) {
val f = new Fraction(n, d)
if (n < 0 && d < 0 || n > 0 && d > 0) f.numer should be > 0
else if (n != 0) f.numer should be < 0
else f.numer shouldBe 0
f.denom should be > 0
}
}}
it should "invalid combos" in {
forAll(Table(
("n", "d"),
(Integer.MIN_VALUE, Integer.MIN_VALUE),
(1, Integer.MIN_VALUE),
(Integer.MIN_VALUE, 1),
(Integer.MIN_VALUE, 0),
(1, 0)
)) { (n: Int, d: Int) =>
an[IllegalArgumentException] should be thrownBy {new Fraction(n, d)}}
}
}
Related
I'm trying to solve problem longest palindromic substring in leetcode in a functional way (using LazyList as cache). However, I got TLE result and I don't know why. Can anyone explain why this code is not efficient?
object Solution {
def longestPalindrome(s: String): String = {
val n = s.length
var ans = (0, 0)
var cnt = 1
def logic(i: Int, j: Int): Int = (i, j) match {
case (i, j) if i > j => -1
case (i, j) if i == j => 1
case (i, j) if s(i) != s(j) => 0
case (i, j) if i + 1 == j => 2
case (i, j) =>
if(mem(i + 1)(j - 1) == 0) 0
else j - i + 1
}
lazy val mem: LazyList[LazyList[Int]] = LazyList.tabulate(n, n) {
case (i, j) => {
val n = logic(i, j)
if(n > cnt) {
cnt = n
ans = (i, j)
}
n
}
}
mem.foreach(_.force)
// println(mem)
ans match {
case (i, j) => s.slice(i, j + 1)
}
}
}
I am wondering if there's a way to deal with a while (n > 0) loop in a more functional way, I have a small Scala app that counts the number of digits equal to K from a range from 1 to N:
for example 30 and 3 would return 4 [3, 13, 23, 30]
object NumKCount {
def main(args: Array[String]): Unit = {
println(countK(30,3))
}
def countKDigit(n:Int, k:Int):Int = {
var num = n
var count = 0
while (num > 10) {
val digit = num % 10
if (digit == k) {count += 1}
num = num / 10
}
if (num == k) {count += 1}
count
}
def countK(n:Int, k:Int):Int = {
1.to(n).foldLeft(0)((acc, x) => acc + countKDigit(x, k))
}
}
I'm looking for a way to define the function countKDigit using a purely functional approach
First expand number n into a sequence of digits
def digits(n: Int): Seq[Int] = {
if (n < 10) Seq(n)
else digits(n / 10) :+ n % 10
}
Then reduce the sequence by counting occurrences of k
def countKDigit(n:Int, k:Int):Int = {
digits(n).count(_ == k)
}
Or you can avoid countKDigit entirely by using flatMap
def countK(n:Int, k:Int):Int = {
1.to(n).flatMap(digits).count(_ == k)
}
Assuming that K is always 1 digit, you can convert n to String and use collect or filter, like below (there's not much functional stuff you can do with Integer):
def countKDigit(n: Int, k: Int): Int = {
n.toString.collect({ case c if c.asDigit == k => true }).size
}
or
def countKDigit(n: Int, k: Int): Int = {
n.toString.filter(c => c.asDigit == 3).length
}
E.g.
scala> 343.toString.collect({ case c if c.asDigit == 3 => true }).size
res18: Int = 2
scala> 343.toString.filter(c => c.asDigit == 3).length
res22: Int = 2
What about the following approach:
scala> val myInt = 346763
myInt: Int = 346763
scala> val target = 3
target: Int = 3
scala> val temp = List.tabulate(math.log10(myInt).toInt + 1)(x => math.pow(10, x).toInt)
temp: List[Int] = List(1, 10, 100, 1000, 10000, 100000)
scala> temp.map(x => myInt / x % 10)
res17: List[Int] = List(3, 6, 7, 6, 4, 3)
scala> temp.count(x => myInt / x % 10 == target)
res18: Int = 2
Counting the occurrences of a single digit in a number sequence.
def countK(n:Int, k:Int):Int = {
assert(k >= 0 && k <= 9)
1.to(n).mkString.count(_ == '0' + k)
}
If you really only want to modify countKDigit() to a more functional design, there's always recursion.
def countKDigit(n:Int, k:Int, acc: Int = 0):Int =
if (n == 0) acc
else countKDigit(n/10, k, if (n%10 == k) acc+1 else acc)
Spock framework contains #Unroll annotation which results in showing each 'case' from parametrized test as a separate test. Is something similar possible with ScalaTest?
A code snippet from the internet which worked for me:
import org.scalatest.FreeSpec
import org.scalatest._
import org.scalatest.prop.TableDrivenPropertyChecks
class OrderValidationTableDrivenSpec extends FreeSpec
with TableDrivenPropertyChecks
with Matchers {
"Order Validation" - {
"should validate and return false if" - {
val orders = Table(
("statement" , "order")
, ("price is negative" , Order(quantity = 10, price = -2))
, ("quantity is negative" , Order(quantity = -10, price = 2))
, ("price and quantity are negative" , Order(quantity = -10, price = -2))
)
forAll(orders) {(statement, invalidOrder) =>
s"$statement" in {
OrderValidation.validateOrder(invalidOrder) shouldBe false
}
}
}
}
}
Imports and class naming may be different depends on scalatest version.
The closest would be the table-driven property checks:
import org.scalatest.prop.TableDrivenPropertyChecks._
val fractions =
Table(
("n", "d"), // First tuple defines column names
( 1, 2), // Subsequent tuples define the data
( -1, 2),
( 1, -2),
( -1, -2),
( 3, 1),
( -3, 1),
( -3, 0),
( 3, -1),
( 3, Integer.MIN_VALUE),
(Integer.MIN_VALUE, 3),
( -3, -1)
)
import org.scalatest.matchers.ShouldMatchers._
forAll (fractions) { (n: Int, d: Int) =>
whenever (d != 0 && d != Integer.MIN_VALUE
&& n != Integer.MIN_VALUE) {
val f = new Fraction(n, d)
if (n < 0 && d < 0 || n > 0 && d > 0)
f.numer should be > 0
else if (n != 0)
f.numer should be < 0
else
f.numer should be === 0
f.denom should be > 0
}
}
There are other techniques such as "sharing tests" and
more property-based testing.
The purpose of my function is to add 5 to an integer as long as that integer is greater than 0 and less than or equal to 7. I try:
val add5Partial : PartialFunction[Int, Int] = {
case d if (0 < d <= 7) => d + 5;
}
I get:
<console>:8: error: type mismatch;
found : Int(7)
required: Boolean
case d if (0 < d <= 7) => d + 5;
Any tips?
Scala do not support such syntax out of the box, so you have to write:
val partial : Int => Int = {
case d if (d > 0) && (d <= 7) => d + 5;
}
Alternatively you could do:
val partial : Int => Int = {
case d if 1 to 7 contains d => d + 5;
}
You can't do this in a single comparison. You need to use:
(d > 0) && (d <= 7)
As you have done it, it will evaluate one comparison to a Boolean and then fail to use this as an int in the second comparison.
You can do any of the following:
val f = (n: Int) ⇒ if (n > 0 && n <= 7) n + 5 else n
// or ...
def f(n: Int) = if (n > 0 && n <= 7) n + 5 else n
// or ...
def f(n: Int): Int = n match {
case n if n > 0 && n <= 7 ⇒ n + 5
case _ ⇒ n
}
// or (to speak of ... the comment by #om-nom-nom)
def f(n: Int) = n match {
case n if 0 to 7 contains n ⇒ n + 5
case _ ⇒ n
}
def comb(c: Int, r: Int): Int = {
if(r == 1) c
else if(r < c) comb(c-1, r-1) + comb(c-1, r)
else 1
}
comb(20,10) //184,756
What I'd like to do is to call it as comb(10,20) and get the same result. I tried to replace c with r and r with c except in the signature, but it doesn't work.
def comb(c: Int, r: Int): Int = {
if(c == 1) r
else if(c < r) comb(r-1, c-1) + comb(r-1, c)
else 1
}
comb(10,20) //2 -> not right
You would also need to change the order in the sub-calls:
def comb(c: Int, r: Int): Int = {
if (c == 1) r
else if (c < r) comb(c - 1, r - 1) + comb(c, r - 1)
else 1
}
This gives the expected result:
comb(10, 20) // 184756
I would add, don't be afraid of local defs:
scala> def comb(c: Int, r: Int): Int = {
| if(r == 1) c
| else if(r < c) comb(c-1, r-1) + comb(c-1, r)
| else 1
| }
comb: (c: Int, r: Int)Int
scala> comb(20,10) //184,756
res0: Int = 184756
scala> def cc(c: Int, r: Int): Int = {
| def cc2(c: Int, r: Int): Int = {
| if(r == 1) c
| else if(r < c) comb(c-1, r-1) + comb(c-1, r)
| else 1
| }
| if (c < r) cc2(r,c) else cc2(c,r)
| }
cc: (c: Int, r: Int)Int
scala> cc(20,10)
res1: Int = 184756
scala> cc(10,20)
res2: Int = 184756