一个scala中的两种方法

时间:2015-02-07 17:34:57

标签: scala methods refactoring field

使用Scala开始我的第一个项目:一个扑克框架。

所以我有以下课程

class Card(rank1: CardRank, suit1: Suit){
val rank = rank1
val suit = suit1
}

包含两种方法的Utils对象几乎完全相同:它们计算每个等级或套装的卡数

def getSuits(cards: List[Card]) = {

def getSuits(cards: List[Card], suits: Map[Suit, Int]): (Map[Suit, Int]) = {
  if (cards.isEmpty)
    return suits

  val suit = cards.head.suit
  val value = if (suits.contains(suit)) suits(suit) + 1 else 1
  getSuits(cards.tail, suits + (suit -> value))

}

getSuits(cards, Map[Suit, Int]())

}


def getRanks(cards: List[Card]): Map[CardRank, Int] = {

def getRanks(cards: List[Card], ranks: Map[CardRank, Int]): Map[CardRank, Int] = {
  if (cards isEmpty)
    return ranks

  val rank = cards.head.rank
  val value = if (ranks.contains(rank)) ranks(rank) + 1 else 1
  getRanks(cards.tail, ranks + (rank -> value))
}

getRanks(cards, Map[CardRank, Int]())
}

有没有什么办法可以用“field / method-as-parameter”将这两种方法“统一”在一起?

由于

1 个答案:

答案 0 :(得分:3)

是的,这需要高阶函数(即将函数作为参数的函数)并输入参数/通用性

def groupAndCount[A,B](elements: List[A], toCount: A => B): Map[B, Int] = {
   // could be your implementation, just note key instead of suit/rank 
   // and change val suit = ... or val rank = ... 
   // to val key = toCount(card.head)
}

然后

def getSuits(cards: List[Card]) = groupAndCount(cards, {c : Card => c.suit})
def getRanks(cards: List[Card]) = groupAndCount(cards, {c: Card => c.rank})

您不需要类型参数A,您可以强制该方法仅在Card上工作,但这可能会很遗憾。

要获得额外的功劳,您可以使用两个参数列表,并拥有

def groupAndCount[A,B](elements: List[A])(toCount: A => B): Map[B, Int] = ...

这是scala与类型推断的一点点特性,如果使用两个参数列表,则在定义函数时不需要键入card参数:

def getSuits(cards: List[Card]) = groupAndCount(cards)(c => c.suit)

或只是

def getSuits(cards: List[Card] = groupAndCount(cards)(_.suit)

当然,图书馆可以帮助您实施

def groupAndCount[A,B](l: List[A])(toCount: A => B) : Map[A,B] =
   l.groupBy(toCount).map{case (k, elems) => (k, elems.length)}

虽然手工制作的实施可能会略微加快。

小调,卡片应声明为case class

case class Card(rank: CardRank, suit: Suit) 
// declaration done, nothing else needed