改变列表并返回删除内容的正确(功能)方法是什么?

时间:2013-09-29 13:23:40

标签: scala

我正在尝试学习scala,并决定创建一个扑克应用程序,让我的头围绕一些类对象。我的甲板工作正常,但我已经到了需要画5张牌的地步。到目前为止,我有:

import util.Random

case class Card(value: Int, color: String)

class Deck {
  private var deck = newDeck 

  def draw(amount: Int): List[Card] = {
    val ret = deck.take(amount)
    deck = deck.drop(amount)
    ret
  }

  def newDeck: List[Card] = {
    Random.shuffle((1 to 13).map(x => 
      List(Card(x, "D"), Card(x, "C"), Card(x, "H"), Card(x, "S"))).toList.flatten)
  }

  override def toString: String =  "Deck has " + deck.length + " cards left."
}

这个绘图功能看起来似乎没有两个步骤 - 但是我不确定我是否可以(或者应该)拿到顶部多个卡片,并将列表保留在没有这些卡片的状态下?

(顺便说一句,如果某人有更好的甲板创建/洗牌功能,我会全神贯注,这看起来有点像hacky ......但我的主要问题是列表状态)

4 个答案:

答案 0 :(得分:2)

撇开您是否希望将套牌设为“var”,您可以使用take

同时执行dropsplitAt
def draw(amount: Int): List[Card] = {
  val (ret, remainder) = deck.splitAt(amount)
  deck = remainder
  ret
}

答案 1 :(得分:2)

解决这个问题的最纯粹的功能方法已经为您编写了!其splitAt,其模型绘制为获取一些卡并返回甲板的新状态。

此技术由集合api中的Queue.dequeue使用:

def dequeue: (A, Queue[A])
//Returns a tuple with the first element in the queue,
//and a new queue with this element removed. 

所以draw只是:

def draw[A](amount: Int): (A, Queue[A]) = deck.splitAt(amount)

答案 2 :(得分:2)

在我看来,你应该重写代码:

完全不可变结构的

(a),即 NO var 无可变集合

(b)将某些可变集合替换为var deck: List[Card],例如ListBuffer

以下是(a)解决方案:

import util.Random

case class Card(value: Int, color: String)

class Deck(private val cards: Seq[Card]) {
  def draw(amount: Int): (Deck, Seq[Card]) = {
    val (ret, rem) = cards.splitAt(amount)
    (new Deck(rem), ret)
  }

  override def toString: String = "Deck has " + cards.size + " cards left."
}

object Deck {
  def apply(cards: Seq[Card] = Nil): Deck = cards match {
    case Nil =>
        val ncds = for(v <- 1 to 13; c <- Seq("D", "C", "H", "S")) yield Card(v, c)
        new Deck(Random.shuffle(ncds))
    case _ => new Deck(cards)
  }
} 

用例:

scala> :paste
// Entering paste mode (ctrl-D to finish)
//paste code here

// Exiting paste mode, now interpreting.

import util.Random
defined class Card
defined class Deck
defined object Deck

scala> val d1 = Deck()
d1: Deck = Deck has 52 cards left.

scala> val (d2, cards) = d1.draw(4)
d2: Deck = Deck has 48 cards left.
cards: Seq[Card] = Vector(Card(3,H), Card(2,S), Card(11,H), Card(8,C))

答案 3 :(得分:1)

只是一个小注意事项:如果您在.flatten方法中使用.flatMap而不是.map,则可以避开newDeck。我不知道为什么你认为这种方法“hacky”,它对我来说看起来非常合理。以下是使用for-syntax的变体:

def newDeck: List[Card] = {
  val sorted = for {
    value <- 1 to 13
    color <- Seq("D", "C", "H", "S")
  } yield Card(value, color)

  Random.shuffle(sorted).toList
}