我是Scala noob。我已经决定编写一个蜘蛛纸牌解算器作为第一个练习语言和函数式编程的练习。
我想生成一张包含1,2或4套西装的随机洗牌。以下是我提出的建议:
val numberOfSuits = 1
(List("clubs", "diamonds", "hearts", "spades").take(numberOfSuits) * 4).take(4)
应返回
List("clubs", "clubs", "clubs", "clubs")
List("clubs", "diamonds", "clubs", "diamonds")
List("clubs", "diamonds", "hearts", "spades")
取决于numberOfSuits的值,除了我没有可以找到的List“multiply”操作。我错过了吗?在改组之前是否有更好的方法来生成完整的牌组?
顺便说一句,我打算在套装上使用枚举,但用字符串输入我的问题会更容易。我将采用上面生成的列表并使用for comprehension,遍历套装和类似的卡片“排名”列表以生成完整的套牌。
答案 0 :(得分:18)
扁平化列表的有限列表:
scala> List.fill(2)(List(1, 2, 3, 4)).flatten
res18: List[Int] = List(1, 2, 3, 4, 1, 2, 3, 4)
展平无限的列表流,取前N个元素:
scala> Stream.continually(List(1, 2, 3, 4)).flatten.take(8).toList
res19: List[Int] = List(1, 2, 3, 4, 1, 2, 3, 4)
答案 1 :(得分:7)
您应该查找对象List
的scaladoc。它有各种有趣的方法来创建列表。例如,以下内容完全符合您的要求:
List.flatten(List.make(4, List("clubs", "diamonds", "hearts", "spades").take(numberOfSuits))).take(4)
然而,更好的代码就是这个(Scala 2.7):
val suits = List("clubs", "diamonds", "hearts", "spades")
List.tabulate(4, i => suits.apply(i % numberOfSuits))
在Scala 2.8上tabulate
是curry,所以正确的语法是:
List.tabulate(4)(i => suits.apply(i % numberOfSuits))
答案 2 :(得分:6)
您可以展开数字序列并flatMap
而不是乘法。
scala> (1 to 3).flatMap(_=>List(1,2,3,4).take(2)).take(4)
res1: Seq[Int] = List(1, 2, 1, 2)
这也适用于2.7.x.
编辑:由于您对Scala的经验不足,您可能还没有遇到过pimp-my-library模式。如果您想要大量增加列表,可以添加自定义转换类:
class MultipliableList[T](l: List[T]) {
def *(n: Int) = (1 to n).flatMap(_=>l).toList
}
implicit def list2multipliable[T](l: List[T]) = new MultipliableList[T](l)
现在你可以
scala> List(1,2,3)*4
res2: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3)
(通常,要重用这些implicits,请在对象中声明它们,然后导入MyObject._以获取隐式转换和范围内的相应类。)
答案 3 :(得分:0)
如果使用cats
库,则可以使用Semigroup
的方法combineN
。它重复列表N
次。
import cats.implicits._
import cats.syntax.semigroup._
scala> List("clubs", "diamonds", "hearts", "spades").combineN(2)
res1: List[String] = List(clubs, diamonds, hearts, spades, clubs, diamonds, hearts, spades)