一个scala中的两种方法
Two methods in one scala
开始我的第一个 Scala 项目:一个扑克框架。
所以我有以下class
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]())
}
有什么办法可以 "unify" 这两种方法与 "field/method-as-parameter" 合而为一吗?
谢谢
是的,这需要高阶函数(即以函数为参数的函数)和类型 parameters/genericity
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 的一个小特点,如果你使用两个参数列表,你将不需要在定义函数时键入卡片参数:
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
开始我的第一个 Scala 项目:一个扑克框架。
所以我有以下class
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]())
}
有什么办法可以 "unify" 这两种方法与 "field/method-as-parameter" 合而为一吗?
谢谢
是的,这需要高阶函数(即以函数为参数的函数)和类型 parameters/genericity
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 的一个小特点,如果你使用两个参数列表,你将不需要在定义函数时键入卡片参数:
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