How can I print all yield output inside of a dunder method in a class? - class

class Number:
def init(self, no):
self.no = no
def __mul__(self,another):
yield self.no *another.no
yield self.no *another.no +1
a = Number(10)
b = Number(5)
print(a*b)

Related

What is a good implementation of generic 2D Array literals in scala3 based on tuples?

The following code is a proof-of-concept for an uncluttered way to declare 2D array literals in scala3. It's based on this answer to a related question, implemented for scala2:
https://stackoverflow.com/a/13863525/666886
The non-generic code below provides a clean Array literal declaration, but is inflexible w.r.t. type and dimension. It would be better to derive array dimensions from tuple arity and number of rows.
#!/usr/bin/env scala3
object Array2d {
def main(args: Array[String]): Unit = {
prettyPrintArray()
}
type X=Int
type Tuple26 = (X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X)
type Array2d = Array[Array[X]]
def apply(tuples: Tuple26 *): Array2d = {
for {
tupe <- tuples
row = for ( i <- tupe.toList ) yield i
} yield row.toArray
}.toArray
lazy val letterFrequencies = Array2d(
(46,615,763,839,1745,325,628,651,1011,128,573,1319,797,1123,884,726,49,1642,2241,1162,631,299,408,97,659,184),
(15,103,128,202,597,49,126,107,358,32,123,321,171,226,483,38,6,439,565,233,340,21,58,21,227,40),
(63,128,106,218,689,86,75,407,526,14,241,369,197,307,627,208,5,507,675,343,361,60,66,24,226,28),
(39,202,218,149,1257,108,183,175,634,35,140,407,212,418,692,194,10,596,763,272,409,97,184,52,348,46),
(745,597,689,1257,919,396,568,583,1214,111,504,1315,726,1083,1217,763,34,1876,2323,1223,662,437,455,199,655,187),
(25,49,86,108,396,118,75,72,295,11,68,258,58,129,248,26,7,299,415,208,205,14,50,20,151,24),
(28,126,75,183,568,75,99,141,424,24,55,324,146,416,476,129,3,423,536,206,326,48,66,4,244,28),
(51,107,407,175,583,72,141,53,399,21,145,282,198,238,488,174,6,342,715,454,285,44,158,14,207,23),
(11,358,526,634,1214,295,424,399,169,71,392,853,518,884,594,467,50,970,1471,853,335,246,215,104,323,130),
(28,32,14,35,111,11,24,21,71,2,31,41,28,52,98,26,1,45,112,33,75,9,12,1,38,3),
(73,123,241,140,504,68,55,145,392,31,61,247,102,300,376,152,8,338,744,184,240,21,86,2,224,20),
(319,321,369,407,1315,258,324,282,853,41,247,250,341,369,875,395,10,468,1237,491,566,173,201,61,463,50),
(97,171,197,212,726,58,146,198,518,28,102,341,102,257,555,195,6,429,769,273,401,33,61,40,260,44),
(123,226,307,418,1083,129,416,238,884,52,300,369,257,159,849,265,18,533,1027,537,499,113,220,45,374,65),
(84,483,627,692,1217,248,476,488,594,98,376,875,555,849,525,566,18,1096,1658,856,462,175,329,85,521,130),
(26,38,208,194,763,26,129,174,467,26,152,395,195,265,566,127,8,488,874,347,353,35,83,24,333,28),
(9,6,5,10,34,7,3,6,50,1,8,10,6,18,18,8,1,16,37,25,96,0,2,0,7,1),
(642,439,507,596,1876,299,423,342,970,45,338,468,429,533,1096,488,16,246,1461,789,673,189,234,52,491,77),
(241,565,675,763,2323,415,536,715,1471,112,744,1237,769,1027,1658,874,37,1461,717,1367,1088,221,484,86,598,105),
(162,233,343,272,1223,208,206,454,853,33,184,491,273,537,856,347,25,789,1367,254,548,72,202,49,384,52),
(31,340,361,409,662,205,326,285,335,75,240,566,401,499,462,353,96,673,1088,548,73,61,41,32,317,51),
(99,21,60,97,437,14,48,44,246,9,21,173,33,113,175,35,0,189,221,72,61,20,25,10,63,7),
(8,58,66,184,455,50,66,158,215,12,86,201,61,220,329,83,2,234,484,202,41,25,11,12,133,19),
(7,21,24,52,199,20,4,14,104,1,2,61,40,45,85,24,0,52,86,49,32,10,12,1,34,2),
(59,227,226,348,655,151,244,207,323,38,224,463,260,374,521,333,7,491,598,384,317,63,133,34,43,54),
(84,40,28,46,187,24,28,23,130,3,20,50,44,65,130,28,1,77,105,52,51,7,19,2,54,42),
)
def prettyPrintArray(): Unit = {
val alphabet = "abcdefghijklmnopqrstuvwxyz"
val toprow = alphabet.map { "%4s".format(_) }.mkString(",")
printf("// %s\n", toprow)
for (a <- alphabet){
val freqs: Seq[String] = for {
b <- alphabet
(x,y) = (alphabet.indexOf(a), alphabet.indexOf(b))
freq = letterFrequencies(x)(y)
} yield "%4d".format(freq)
printf("/* %s */ (%s),\n", a, freqs.mkString(","))
}
}
}
The following works, but the same thing based on the new scala 3 type IArray would be nice to have as well.
#!/usr/bin/env scala3
// Example of declaring a generic NxN Array[Array[_]] in scala3 by using
// scala 3 tuple extensions, for a concise declaration of a 2d array.
// An improved version would avoid the deprecated ClassTag reference,
// and the use of `asInstanceOf[List[T]]`.
// Perhaps `shapeless 3` would help in this regard?
object Array2d {
def main(args: Array[String]): Unit = {
prettyPrintArray()
}
// it would be nice if a Tuple with a single homogeneous field Type
// automatically converted to an Array of that type, rather
// than an Array[AnyRef]
import scala.reflect.ClassTag
def apply[T:ClassTag](tuples: Tuple *): Array[Array[T]] = {
val rows: Seq[Array[T]] = for {
tupe <- tuples
row: Seq[T] = tupe.toList.asInstanceOf[List[T]]
arr: Array[T] = (for (i:T <- row) yield i).toArray
} yield arr
rows.toArray
}
// this table is useful for analyzing nytimes Wordle guesses.
lazy final val letterFrequencies = Array2d[Int](
(46,615,763,839,1745,325,628,651,1011,128,573,1319,797,1123,884,726,49,1642,2241,1162,631,299,408,97,659,184),
(15,103,128,202,597,49,126,107,358,32,123,321,171,226,483,38,6,439,565,233,340,21,58,21,227,40),
(63,128,106,218,689,86,75,407,526,14,241,369,197,307,627,208,5,507,675,343,361,60,66,24,226,28),
(39,202,218,149,1257,108,183,175,634,35,140,407,212,418,692,194,10,596,763,272,409,97,184,52,348,46),
(745,597,689,1257,919,396,568,583,1214,111,504,1315,726,1083,1217,763,34,1876,2323,1223,662,437,455,199,655,187),
(25,49,86,108,396,118,75,72,295,11,68,258,58,129,248,26,7,299,415,208,205,14,50,20,151,24),
(28,126,75,183,568,75,99,141,424,24,55,324,146,416,476,129,3,423,536,206,326,48,66,4,244,28),
(51,107,407,175,583,72,141,53,399,21,145,282,198,238,488,174,6,342,715,454,285,44,158,14,207,23),
(11,358,526,634,1214,295,424,399,169,71,392,853,518,884,594,467,50,970,1471,853,335,246,215,104,323,130),
(28,32,14,35,111,11,24,21,71,2,31,41,28,52,98,26,1,45,112,33,75,9,12,1,38,3),
(73,123,241,140,504,68,55,145,392,31,61,247,102,300,376,152,8,338,744,184,240,21,86,2,224,20),
(319,321,369,407,1315,258,324,282,853,41,247,250,341,369,875,395,10,468,1237,491,566,173,201,61,463,50),
(97,171,197,212,726,58,146,198,518,28,102,341,102,257,555,195,6,429,769,273,401,33,61,40,260,44),
(123,226,307,418,1083,129,416,238,884,52,300,369,257,159,849,265,18,533,1027,537,499,113,220,45,374,65),
(84,483,627,692,1217,248,476,488,594,98,376,875,555,849,525,566,18,1096,1658,856,462,175,329,85,521,130),
(26,38,208,194,763,26,129,174,467,26,152,395,195,265,566,127,8,488,874,347,353,35,83,24,333,28),
(9,6,5,10,34,7,3,6,50,1,8,10,6,18,18,8,1,16,37,25,96,0,2,0,7,1),
(642,439,507,596,1876,299,423,342,970,45,338,468,429,533,1096,488,16,246,1461,789,673,189,234,52,491,77),
(241,565,675,763,2323,415,536,715,1471,112,744,1237,769,1027,1658,874,37,1461,717,1367,1088,221,484,86,598,105),
(162,233,343,272,1223,208,206,454,853,33,184,491,273,537,856,347,25,789,1367,254,548,72,202,49,384,52),
(31,340,361,409,662,205,326,285,335,75,240,566,401,499,462,353,96,673,1088,548,73,61,41,32,317,51),
(99,21,60,97,437,14,48,44,246,9,21,173,33,113,175,35,0,189,221,72,61,20,25,10,63,7),
(8,58,66,184,455,50,66,158,215,12,86,201,61,220,329,83,2,234,484,202,41,25,11,12,133,19),
(7,21,24,52,199,20,4,14,104,1,2,61,40,45,85,24,0,52,86,49,32,10,12,1,34,2),
(59,227,226,348,655,151,244,207,323,38,224,463,260,374,521,333,7,491,598,384,317,63,133,34,43,54),
(84,40,28,46,187,24,28,23,130,3,20,50,44,65,130,28,1,77,105,52,51,7,19,2,54,42),
)
def prettyPrintArray(): Unit = {
val alphabet = "abcdefghijklmnopqrstuvwxyz"
val toprow = alphabet.map { "%4s".format(_) }.mkString(",")
printf("// %s\n", toprow)
for (a <- alphabet){
val freqs: Seq[String] = for {
b <- alphabet
(x,y) = (alphabet.indexOf(a), alphabet.indexOf(b))
freq = letterFrequencies(x)(y)
} yield "%4d".format(freq)
printf("/* %s */ (%s),\n", a, freqs.mkString(","))
}
}
}

Scala - Perfect Number usage in higher order function - anything wrong?

Apologies , but am new to scala... learning it, now.
I have been trying to complete a excercise where the ask was as follows :-
// Write a function isPerfectNumber which takes integer input and returns String output.
// It finds if a number is perfect, and returns true if perfect, else returns false
// Write a higher order function myHigherOrderFunction which takes isPerfectNumber and intList as input, and returns a List of Strings which contain the output if the number is perfect or not using map.
Perfect Number :
https://rosettacode.org/wiki/Perfect_numbers
just go to the scala section
My Code :
object ListMapHigherOrder{
def main(args:Array[String])
{
val intRes = args.toList
val intList: List[Int] = intRes.map(_.toInt).toList
def isPerfectNumber(input: Int) :String =
{
var check_sum = ( (2 to math.sqrt(input).toInt).collect { case x if input % x == 0 => x + input / x} ).sum
if ( check_sum == input - 1 )
return "true"
else
return "false"
}
def myHigherOrderFunction(argFn: Int => String, argVal:List[Int]): List[String] = { argVal.map(argFn) }
println(myHigherOrderFunction(isPerfectNumber, intList))
}
}
Code execution : scala ScalaExcercise12.scala 1 6 13
Expected Output : List(false , true , false)
the code gives expected output, am not sure how the backend testing is being done.... it just dosent pass the test.
Is there any issue with the code? - i did like to fix it , but cant i see anything wrong/missing especially because i am getting the same output as desired :(
object ListMapHigherOrder{
def main(args:Array[String])
{
val intRes = args.toList
val intList: List[Int] = intRes.map(x=>x.toInt)
def isPerfectNumber(input: Int) :String =
{
var sum = 0
for(i <- 1 until input){
if(input % i == 0)
sum = sum+i
}
if ( sum == input )
return "true"
else
return "false"
}
def myHigherOrderFunction(argFn: Int => String, argVal:List[Int]): List[String] = { argVal.map(argFn) }
println(myHigherOrderFunction(isPerfectNumber, intList))
}
}
**This worked for me

Scala Trait Mixin order

object sandbox {
class Numbers {
def price() : List[Int] = List(1,3,5,7)
def printIt(): Unit = {
price.foreach(x => print(x+ " ") )
}
}
trait DoubleIt extends Numbers {
override def price() : List[Int] ={
println("doubling")
super.price.map(x => x*2)
}
}
trait AddIt extends Numbers {
override def price() : List[Int] = {
println("adding")
super.price.map( x => x+2)
}
}
def main(args :Array[String]): Unit = {
val obj = new Numbers with DoubleIt with AddIt
obj.printIt()
}
}
//output :
adding
doubling
4 8 12 16
In the above code, price() method from AddIt trait executes first (from print statement).But shouldn't the value be 6 10 14 18? Why the values are doubled before adding?
The result makes sense:
printIt calls AddIt.price
AddIt.price calls DoubleIt.price, and then adds 2 to each one
DoubleIt.price calls Numbers.price, and then dubles each one, returning List(2,6,10,14)
This means that AddIt.price returns List(2+2, 6+2, 10+2, 14+2), which is indeed the printed result
The key here is understanding that indeed AddIt.price starts before DoubleIt.price, but it uses the result of DoubleIt.price to create the return value, before the addition.
Your traits are stacked in the order that you declare them:
AddIt
DoubleIt
Numbers
When you run printIt, you're doing it on an AddIt, resulting in the following call chain:
AddIt.printIt
AddIt.printIt.price //here you get to print "adding"
AddIt.price.super.price //calls DoubleIt's price
DoubleIt.price //here you get to print "doubling"
DoubleIt.super.price //calls Number's price
Numbers.price //returns List(1, 3, 5, 7)
DoubleIt.super.price.map //doubles your list input
AddIt.super.price.map //adds 2 to the result
AddIt.printIt.foreach //prints the final result

Incrementing 'i' in scala for loop by differing amounts depending on circumstance

I want to write a for loop in scala, but the counter should get incremented by more than one (the amount is variable) in some special cases.
You can do this with a combination of a filter and an external var. Here is an example:
var nextValidVal = 0
for (i <- 0 to 99; if i >= nextValidVal) {
var amountToSkip = 0
// Whatever this loop is for
nextValidVal = if (amountToSkip > 0) i + amountToSkip + 1 else nextValidVal
}
So in the main body of your loop, you can set amountToSkip to n according to your conditions. The next n values of i´s sequence will be skipped.
If your sequence is pulled from some other kind of sequence, you could do it like this
var skip = 0
for (o <- someCollection if { val res = skip == 0; skip = if (!res) skip - 1 else 0; res } ) {
// Do stuff
}
If you set skip to a positive value in the body of the loop, the next n elements of the sequence will be skipped.
Of course, this is terribly imperative and side-effecty. I would look for other ways to to this where ever possible, by mapping or filtering or folding the original sequence.
You could implement your own stream to reflect step, for example:
import scala.collection.immutable.Stream
import ForStream._
object Test {
def main(args: Array[String]): Unit = {
val range = 0 to 20 by 1 withVariableStep; // in case you like definition through range
//val range = ForStream(0,20,1) // direct definition
for (i<- range) {
println(s"i=$i")
range.step = range.step + 1
}
}
}
object ForStream{
implicit def toForStream(range: Range): ForStream = new ForStreamMaster(range.start, range.end,range.step)
def apply(head:Int, end:Int, step:Int) = new ForStreamMaster(head, end,step)
}
abstract class ForStream(override val head: Int, val end: Int, var step: Int) extends Stream[Int] {
override val tailDefined = false
override val isEmpty = head > end
def withVariableStep = this
}
class ForStreamMaster(_head: Int, _end: Int, _Step: Int) extends ForStream(_head, _end,_Step){
override def tail = if (isEmpty) Stream.Empty else new ForStreamSlave(head + step, end, step, this)
}
class ForStreamSlave(_head: Int, _end: Int, _step: Int, val master: ForStream) extends ForStream(_head, _end,_step){
override def tail = if (isEmpty) Stream.Empty else new ForStreamSlave(head + master.step, end, master.step, master)
}
This prints:
i=0
i=2
i=5
i=9
i=14
i=20
You can define ForStream from Range with implicits, or define it directly. But be carefull:
You are not iterating Range anymore!
Stream should be immutable, but step is mutable!
Also as #om-nom-nom noted, this might be better implemented with recursion
Why not use the do-while loop?
var x = 0;
do{
...something
if(condition){change x to something else}
else{something else}
x+=1
}while(some condition for x)

An example of functional programming in scala

I'm studying scala. It's very promising, thanks to Odersky and all the other authors for their great work.
I took a euler problem (http://projecteuler.net/) to have a more-then-minimal example. And I'm trying to go the functional way. So this is not a "please answer me immediatly or my boss will kill me" but a "please if you've got time, can you help a imperative language programmer to take a journey in the functional world?"
Problem: I want a class for poker hands. A poker Hand is composed by a number of Card, from 0 to 5. I'd like to build the list of Cards one and for all, that is: my Hand class will be immutable, if I want to add a card, then I create a new Hand object.
So I need a collection of Card that can be created as "val", not as var.
First step: constructors, one for each number of cards. But Card's collection is handled in each constructor, so I must have it as var!
Here's the code, Card class is simply a Suit and a Value, passed to constructor as a string ("5S" is the 5 of spades):
class Hand(mycards : List[Card]) {
// this should be val, I guess
private var cards : List[Card] = {
if (mycards.length>5)
throw new IllegalArgumentException(
"Illegal number of cards: " + mycards.length);
sortCards(mycards)
}
// full hand constructor
def this(a : String, b : String, c : String, d : String, e : String) = {
this(Nil)
// assign cards
val cardBuffer = new ListBuffer[Card]()
if ( a!=null ) cardBuffer += new Card(a)
if ( b!=null ) cardBuffer += new Card(b)
if ( c!=null ) cardBuffer += new Card(c)
if ( d!=null ) cardBuffer += new Card(d)
if ( e!=null ) cardBuffer += new Card(e)
cards = sortCards(cardBuffer.toList)
}
// hand with less then 5 cards
def this(a : String, b : String, c : String, d : String) = this(a,b,c,d,null)
def this(a : String, b : String, c : String) = this(a, b, c, null)
def this(a : String, b : String) = this(a, b, null)
def this(a : String) = this(a, null)
def this() = this(Nil)
/* removed */
}
Do you know how to make it the true functional way?
Thanks.
PS: if you really want to know, it's problem 54.
My answer is not about functional aspect of scala, but your code is possible to write shortly using scala sugar:
class Hand(val mycards: List[Card]) {
require (mycards.size <= 5,"can't be more than five cards")
def this(input: String*) = {
this(input.map(c => new Card(c)).toList)
}
}
input: String* in auxiliary constructor says that you can have variable number of arguments (even thousand of strings).
I'm getting input and invoke creation for each new Card with map function, and then pass result to parent constructor which has it's own requirement.
(BTW, mapping from string to Card can be done anonymously, in that manner: this(input.map(new Card(_)).toList))
class Hand(val mycards: List[Card]) {...
Is equable to
class Hand(cards: List[Card]) {
val mycards = cards
...
From now on, if you will try to create more than five cards in hand you'll get java.lang.IllegalArgumentException:
scala> class Card(s: String) {println("Im a :"+s)}
defined class Card
scala> new Hand("one","two","three","four","five","six")
Im a :one
Im a :two
Im a :three
Im a :four
Im a :five
Im a :six
java.lang.IllegalArgumentException: requirement failed: can't be more than five card
at scala.Predef$.require(Predef.scala:157)
at Hand.<init>(<console>:9)
Well, the the var in the code below comes from you not initializing cards from the main constructor:
// this should be val, I guess
private var cards : List[Card] = {
if (mycards.length>5)
throw new IllegalArgumentException(
"Illegal number of cards: " + mycards.length);
sortCards(mycards)
}
So what you need to do is fix the secondary constructor:
// full hand constructor
def this(a : String, b : String, c : String, d : String, e : String) = {
this(Nil)
// assign cards
val cardBuffer = new ListBuffer[Card]()
if ( a!=null ) cardBuffer += new Card(a)
if ( b!=null ) cardBuffer += new Card(b)
if ( c!=null ) cardBuffer += new Card(c)
if ( d!=null ) cardBuffer += new Card(d)
if ( e!=null ) cardBuffer += new Card(e)
cards = sortCards(cardBuffer.toList)
}
THe problemn is simple: you want a list of cards formed by non-null Strings. If I were you, I'd just avoid passing nulls, but... Anyway, the best way to handle that is to convert this into options. The conversion is simple: Option(a) will return Some(a) is a is not null, and None if it is. If you compose a list of that, you can then flatten it to remove the None and convert Some(a) back into a. In other words:
def this(a : String, b : String, c : String, d : String, e : String) =
this(List(a, b, c, d, e).map(Option(_)).flatten.map(Card(_)))
Because in this example you are only allowed to use five cards I would check this at compile time with the use of a Tuple5:
type HandType = (ACard, ACard, ACard, ACard, ACard)
case class Hand(h: HandType)
abstract class ACard {
def exists: Boolean
}
case class Card(value: Int, color: Color) extends ACard {
def exists = true
}
case object NoCard extends ACard {
def exists = false
}
abstract class Color(val c: Int)
case object H extends Color(1)
case object C extends Color(2)
case object S extends Color(3)
case object D extends Color(4)
case object NoColor extends Color(0)
implicit def tuple2Card(t: (Int, Color)) = Card(t._1, t._2)
val h1 = Hand((Card(4, H), Card(6, S), Card(2, S), Card(8, D), NoCard))
val h2 = Hand((4 -> H, 6 -> S, 2 -> S, 8 -> D, NoCard))
println(h1)
println(h2)
h1.h.productIterator foreach { c => println(c.asInstanceOf[ACard].exists) }
Of course in another example when there can be an unspecific number of elements you need to check them at runtime. productIterator only returns a Iterator[Any] but when you use your cards directly by the field-identifiers (_1 .. _5) you will get an ACard.
Firstly, null is evil, use Option instead. Secondly, Scala supports default parameters. So instead of creating all the constructors, you might just wanna use one of them like this:
def this(a: String = null, ..., e: String = null) = ...
or with Option, which is safer.
def this(a: Option[String] = None, ..., e: Option[String] = None) = {
this(Nil)
val cardBuffer = new ListBuffer[Card]()
a foreach { cardBuffer += new Card(_) }
b foreach { cardBuffer += new Card(_) }
c foreach { cardBuffer += new Card(_) }
d foreach { cardBuffer += new Card(_) }
e foreach { cardBuffer += new Card(_) }
cards = sortCards(cardBuffer.toList)
}
So the cards are only added to the buffer if they "exist".
First, we need to fix a compile error in your cards field definition.
Note that in Scala you usually don't have to declare fields. Main constructor parameters already are fields! So, this can be written simpler:
class Hand(cards : List[Card]) {
if (cards.length>5)
throw new IllegalArgumentException(
"Illegal number of cards: " + mycards.length);
Now we have mutability problem. If you want to program in functional style, everything should be immutable, so the "full hand constructor" is not functional at all: it has 6 side-effecting operations, last of which does not compile.
In functional setting, an object can't be modified after its constructor has terminated, so all the code after this(Nil) is useless. You already said that cards is Nil, what else do you want?! So, all the computations have to happen before the main constructor call. We'd like to remove this(Nil) from the top and add this(sortCards(cardBuffer.toList)) to the bottom. Unfortunately, Scala does not allow that. Fortunately, it allows more options to achieve the same than java: first, you can use a nested block like this:
this({
val cardBuffer = ... /* terrible imperativeness */
sortCards(cardBuffer.toList)
})
second, you can use apply method instead of a constructor:
object Hand {
def apply(a : String, b : String, c : String, d : String, e : String) = {
val cardBuffer = ... /* terrible imperativeness */
new Hand(sortCards(cardBuffer.toList))
}
}
Now, let's start getting rid of imperative ListBuffer. First improvement would be to use var of type List[Card]. Making mutability more local will help to remove it later:
// assign cards
var cards = Nil
if ( e!=null ) cards = new Card(e) :: cards
if ( d!=null ) cards = new Card(d) :: cards
if ( c!=null ) cards = new Card(c) :: cards
if ( b!=null ) cards = new Card(b) :: cards
if ( a!=null ) cards = new Card(a) :: cards
sortCards(cards)
Okay, now we can see what exactly we are mutating and can easily remove that mutability:
val fromE = if ( e!=null ) new Card(e) :: Nil else Nil
val fromD = if ( d!=null ) new Card(d) :: fromE else fromE
val fromC = if ( c!=null ) new Card(c) :: fromD else fromD
val fromB = if ( b!=null ) new Card(b) :: fromC else fromC
val fromA = if ( a!=null ) new Card(a) :: fromB else fromB
sortCards(fromA)
Now we have a fair amount of code duplication. Let's remove that in a brute-force way (find a long duplicating piece of code and extract function)!
def prependCard(x : String, cards : List[Card]) =
if ( x!=null ) new Card(x) :: cards else cards
val cards = prependCard(a, prependCard(b,
prependCard(c, prependCard(d,
prependCard(e, Nil)
))
))
sortCards(cards)
Next, very important, transformation would be to replace nullable references with the values of Option type, or remove the empty card concept altogether.
Update:
As requested, I am adding an example of usage of the apply method. Notice that it is declared in object Hand, not class Hand, so it doesn't need an instance of the class (it's similar to static method in java). We just apply the object to parameters: val hand = Hand("5S", "5S", "5S", "5S", "5S").
Attempt using varargs, overloaded + operator, repeated addition in constructor, and Set to eliminate duplicate cards.
package poker
class Hand(private val cards:Set[Card] = Set.empty[Card]) {
def + (card:Card) = {
val hand = new Hand(cards + card)
require(hand.length > length, "Card %s duplicated".format(card))
require(hand.length <= Hand.maxLength, "Hand length > %d".format(Hand.maxLength))
hand
}
def length = cards.size
override def toString = cards.mkString("(", ",", ")")
}
object Hand {
val maxLength = 5
def apply(cards:Card*):Hand = cards.foldLeft(Hand())(_ + _)
private def apply() = new Hand()
}
//-----------------------------------------------------------------------------------------------//
class Card private (override val toString:String)
object Card {
def apply(card:String) = {
require(cardMap.contains(card), "Card %s does not exist".format(card))
cardMap(card)
}
def cards = cardMap.values.toList
private val cardMap = {
val ranks = Range(2,9).inclusive.map { _.toString } ++ List("T", "J", "Q", "K", "A")
val suits = List("c","d","h","s")
(for(r <- ranks; s <- suits) yield (r + s -> new Card(r + s))).toMap
}
}
//-----------------------------------------------------------------------------------------------//
object Test extends App {
Array("1f", "Ac").foreach { s =>
try {
printf("Created card %s successfully\n",Card(s))
} catch {
case e:Exception => printf("Input string %s - %s \n", s, e.getMessage)
}
}
println
for(i <- 0 to 6) {
val cards = Card.cards.slice(0, i)
makeHand(cards)
}
println
val cards1 = List("Ac","Ad","Ac").map { Card(_) }
makeHand(cards1)
println
val hand1 = Hand(List("Ac","Ad").map { Card(_) }:_* )
val card = Card("Ah")
val hand2 = hand1 + card
printf("%s + %s = %s\n", hand1, card, hand2)
def makeHand(cards:List[Card]) =
try {
val hand = Hand(cards: _*)
printf("Created hand %s successfully\n",hand)
} catch {
case e:Exception => printf("Input %s - %s \n", cards, e.getMessage)
}
}