Hi all I am new with Scala and I have a doubt:
Creation of sublists with elements 1 and 2 in alternate ways, never having two consecutive numbers repeated.
My function:
def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
//What should be the solution?
}
Tests:
test("AlternateElementsTests") {
assert(ca1.functionAlternateElements(List(1)) === Some(List(1)))
assert(ca1.functionAlternateElements(List(1,2)) === Some(List(2)))
assert(ca1.functionAlternateElements(List(1,2,3)) === Some(List(1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4)) === Some(List(1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5)) === Some(List(2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6)) === Some(List(1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7)) === Some(List(1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8)) === Some(List(2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9)) === Some(List(1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10)) === Some(List(1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11)) === Some(List(2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14)) === Some(List(2, 1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)) === Some(List(2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2)))
}
How can I do this?
If you know the code can you give an explanation so I can understand it please?
Given that the assertions seem to be more or less arbitrary, I don't know how to write a program that can produce these strange outputs.
However, I know how to write a program that can write a program that can produce these strange outputs. The idea is to generate code that satisfies the requirements. We will generate it by supplying an ansatz and then searching for a bunch of magic numbers by brute-force.
First, let's build some infrastructure. We need a tiny framework for solving arbitrary problems by brute force. Here is a trait that is useful for very small problems:
trait BruteForce[X] {
def engageBruteForceAttack(constraint: X => Boolean): Option[X]
def zip[Y](other: BruteForce[Y]): BruteForce[(X, Y)] =
new ProductBruteForce[X, Y](this, other)
}
We need to handle only the finite case and the case of cartesian product:
class FiniteBruteForce[X](possibilities: List[X])
extends BruteForce[X] {
def engageBruteForceAttack(constraint: X => Boolean) = possibilities.find(constraint)
}
object FiniteBruteForce {
def apply[X](xs: X*) = new FiniteBruteForce[X](xs.toList)
}
class ProductBruteForce[A, B](a: BruteForce[A], b: BruteForce[B])
extends BruteForce[(A, B)] {
def engageBruteForceAttack(constraint: ((A, B)) => Boolean) = {
var solution: Option[(A, B)] = None
a.engageBruteForceAttack { x =>
b.engageBruteForceAttack { y =>
if (constraint((x, y))) {
solution = Some((x, y))
true
} else {
false
}
}.map(_ => true).getOrElse(false)
}
solution
}
}
Now we can extract the inputs and outputs from your test cases:
val mysteriousTestCases = List(
(List(1), List(1)),
(List(1,2), List(2)),
(List(1,2,3), List(1, 2)),
(List(1,2,3,4), List(1, 2, 1)),
(List(1,2,3,4,5), List(2, 1, 2)),
(List(1,2,3,4,5,6), List(1, 2, 1, 2)),
(List(1,2,3,4,5,6,7), List(1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8), List(2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9), List(1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10), List(1, 2, 1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8,9,10,11), List(2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12), List(1, 2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13), List(1, 2, 1, 2, 1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14), List(2, 1, 2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17), List(2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2))
)
Now let's write a program that will write us the function that computes the strange 1,2,1,1,2,... sequence:
val (illuminatiPivot, (illuminatiOffset, illuminatiShift)) =
FiniteBruteForce(-1, -2, 0, 1, 2).zip(
FiniteBruteForce(-1, -2, 1, 2, 3).zip(
FiniteBruteForce(0, 1, 2)
)
).engageBruteForceAttack{ case (p, (o, s)) =>
mysteriousTestCases.forall { case (input, output) =>
val (start :: tail) = output
val n = input.size
val illuminatiNumber =
if (n < p) (n + o)
else List(1, 1, 2)((n + s) % 3)
start == illuminatiNumber
}
}.get
println(s"""|// The function that generates the start number
|// of the strange sequences
|def illuminatiNumber(n: Int): Int = {
| if (n < $illuminatiPivot) (n + $illuminatiOffset)
| else List(1, 1, 2)((n + $illuminatiShift) % 3)
|}
|""".stripMargin)
Now do the same for the lengths of the outputs. The ansatz is this time: it should be some affine-linear function that grows with factor 2/3 and is rounded in a weird way:
val (hl3ConfirmedConst, hl3ConfirmedOffset) =
FiniteBruteForce(-2, -1, 0, 1, 2).zip(
FiniteBruteForce(-2, -1, 0, 1, 2, 3)
).engageBruteForceAttack{ case (c, o) =>
mysteriousTestCases.forall { case (input, output) =>
val n = input.size
val halfLife3Confirmed = c + (n * 2 + o) / 3
output.size == halfLife3Confirmed
}
}.get
println(s"""|def halfLife3Confirmed(i: Int): Int = {
| $hl3ConfirmedConst + (i * 2 + $hl3ConfirmedOffset) / 3
|}
|""".stripMargin)
Finally, I didn't bother to think hard enough how to map 1 to sequence 1,2,1,2,... and 2 to 2,1,2,1,..., so I brute-forced this too:
val (tabulationOffset, tabulationShift) =
FiniteBruteForce(-1, 0, 1, 2).zip(FiniteBruteForce(0, 1)).engageBruteForceAttack{
case (x, y) =>
(0 to 2).map(i => x + (y + 1 + i) % 2).toList == List(1, 2, 1) &&
(0 to 2).map(i => x + (y + 2 + i) % 2).toList == List(2, 1, 2)
}.get
Now we can write out the initially seeked functionAlternateElements-method:
println(s"""|def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
| val n = list.size // throw away everything but the size
| val resultStart = illuminatiNumber(n)
| val resultSize = halfLife3Confirmed(n)
| Some(List.tabulate(resultSize){ i => $tabulationOffset + ($tabulationShift + resultStart + i) % 2 })
|}
|""".stripMargin)
Let's also write out the assertions again:
for ((i, o) <- mysteriousTestCases) {
val input = i.mkString("List(", ",", ")")
val output = o.mkString("List(", ",", ")")
println(s"""assert(functionAlternateElements($input) == Some($output))""")
}
And also let's append a line that tells us that everything went well in the end:
println("""println("All assertions are true")""")
When run, the above contraption produces the following code:
// The function that generates the start number
// of the strange sequences
def illuminatiNumber(n: Int): Int = {
if (n < -1) (n + -1)
else List(1, 1, 2)((n + 0) % 3)
}
def halfLife3Confirmed(i: Int): Int = {
0 + (i * 2 + 1) / 3
}
def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
val n = list.size // throw away everything but the size
val resultStart = illuminatiNumber(n)
val resultSize = halfLife3Confirmed(n)
Some(List.tabulate(resultSize){ i => 1 + (1 + resultStart + i) % 2 })
}
assert(functionAlternateElements(List(1)) == Some(List(1)))
assert(functionAlternateElements(List(1,2)) == Some(List(2)))
assert(functionAlternateElements(List(1,2,3)) == Some(List(1,2)))
assert(functionAlternateElements(List(1,2,3,4)) == Some(List(1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5)) == Some(List(2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6)) == Some(List(1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7)) == Some(List(1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8)) == Some(List(2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9)) == Some(List(1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10)) == Some(List(1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11)) == Some(List(2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12)) == Some(List(1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13)) == Some(List(1,2,1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14)) == Some(List(2,1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)) == Some(List(1,2,1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) == Some(List(1,2,1,2,1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)) == Some(List(2,1,2,1,2,1,2,1,2,1,2)))
println("All assertions are true")
When we execute the generated code, we get only:
All assertions are true
and no AssertionErrors. Thus, we've managed to implement the strange function successfully.
Tip of the day: you know that your specification is bad when the only way to satisfy the tests is by brute-forcing a bunch of magic numbers.
This is my first day using scala. I am trying to make a string of the number of times each digit is represented in a string. For instance, the number 4310227 would return "1121100100" because 0 appears once, 1 appears once, 2 appears twice and so on...
def pow(n:Int) : String = {
val cubed = (n * n * n).toString
val digits = 0 to 9
val str = ""
for (a <- digits) {
println(a)
val b = cubed.count(_==a.toString)
println(b)
}
return cubed
}
and it doesn't seem to work. would like some scalay reasons why and to know whether I should even be going about it in this manner. Thanks!
When you iterate over strings, which is what you are doing when you call String#count(), you are working with Chars, not Strings. You don't want to compare these two with ==, since they aren't the same type of object.
One way to solve this problem is to call Char#toString() before performing the comparison, e.g., amend your code to read cubed.count(_.toString==a.toString).
As Rado and cheeken said, you're comparing a Char with a String, which will never be be equal. An alternative to cheekin's answer of converting each character to a string is to create a range from chars, ie '0' to '9':
val digits = '0' to '9'
...
val b = cubed.count(_ == a)
Note that if you want the Int that a Char represents, you can call char.asDigit.
Aleksey's, Ren's and Randall's answers are something you will want to strive towards as they separate out the pure solution to the problem. However, given that it's your first day with Scala, depending on what background you have, you might need a bit more context before understanding them.
Fairly simple:
scala> ("122333abc456xyz" filter (_.isDigit)).foldLeft(Map.empty[Char, Int]) ((histo, c) => histo + (c -> (histo.getOrElse(c, 0) + 1)))
res1: scala.collection.immutable.Map[Char,Int] = Map(4 -> 1, 5 -> 1, 6 -> 1, 1 -> 1, 2 -> 2, 3 -> 3)
This is perhaps not the fastest approach because intermediate datatype like String and Char are used but one of the most simplest:
def countDigits(n: Int): Map[Int, Int] =
n.toString.groupBy(x => x) map { case (n, c) => (n.asDigit, c.size) }
Example:
scala> def countDigits(n: Int): Map[Int, Int] = n.toString.groupBy(x => x) map { case (n, c) => (n.asDigit, c.size) }
countDigits: (n: Int)Map[Int,Int]
scala> countDigits(12345135)
res0: Map[Int,Int] = Map(5 -> 2, 1 -> 2, 2 -> 1, 3 -> 2, 4 -> 1)
Where myNumAsString is a String, eg "15625"
myNumAsString.groupBy(x => x).map(x => (x._1, x._2.length))
Result = Map(2 -> 1, 5 -> 2, 1 -> 1, 6 -> 1)
ie. A map containing the digit with its corresponding count.
What this is doing is taking your list, grouping the values by value (So for the initial string of "15625", it produces a map of 1 -> 1, 2 -> 2, 6 -> 6, and 5 -> 55.). The second bit just creates a map of the value to the count of how many times it occurs.
The counts for these hundred digits happen to fit into a hex digit.
scala> val is = for (_ <- (1 to 100).toList) yield r.nextInt(10)
is: List[Int] = List(8, 3, 9, 8, 0, 2, 0, 7, 8, 1, 6, 9, 9, 0, 3, 6, 8, 6, 3, 1, 8, 7, 0, 4, 4, 8, 4, 6, 9, 7, 4, 6, 6, 0, 3, 0, 4, 1, 5, 8, 9, 1, 2, 0, 8, 8, 2, 3, 8, 6, 4, 7, 1, 0, 2, 2, 6, 9, 3, 8, 6, 7, 9, 5, 0, 7, 6, 8, 7, 5, 8, 2, 2, 2, 4, 1, 2, 2, 6, 8, 1, 7, 0, 7, 6, 9, 5, 5, 5, 3, 5, 8, 2, 5, 1, 9, 5, 7, 2, 3)
scala> (new Array[Int](10) /: is) { case (a, i) => a(i) += 1 ; a } map ("%x" format _) mkString
warning: there were 1 feature warning(s); re-run with -feature for details
res7: String = a8c879caf9
scala> (new Array[Int](10) /: is) { case (a, i) => a(i) += 1 ; a } sum
warning: there were 1 feature warning(s); re-run with -feature for details
res8: Int = 100
I was going to point out that no one used a char range, but now I see Kristian did.
def pow(n:Int) : String = {
val cubed = (n * n * n).toString
val cnts = for (a <- '0' to '9') yield cubed.count(_ == a)
(cnts map (c => ('0' + c).toChar)).mkString
}