我刚刚开始使用Scala。我发现自己经常使用元组变量。例如,这里是我写的一些代码:
/* Count each letter of a string and return in a list sorted by character
* countLetter("test") = List(('e',1),('s',1),('t',2))
*/
def countLetters(s: String): List[(Char, Int)] = {
val charsListMap = s.toList.groupBy((c:Char) => c)
charsListMap.map(x => (x._1, x._2.length)).toList.sortBy(_._1)
}
这个元组sytax(x._1,x._2等)是否受到Scala开发人员的不满?
答案 0 :(得分:27)
Scala开发人员对元组访问器不满意吗?
简答:不。
稍微长一点(按一个字符)答案:是的。
太多_n
可能是代码气味,在您看来,以下内容更清晰,我认为:
def countLetters(s: String): List[(Char, Int)] =
s.groupBy(identity).mapValues(_.length).toList.sortBy(_._1)
有很多像mapValues
这样的方法专门用于减少对嘈杂的元组访问器的需求,所以如果你发现自己写了很多_1
等等,那很可能意味着你错过了一些不错的库方法。但偶尔他们是写一些东西的最干净的方法(例如,我的重写中的最后_1
)。
另外需要注意的是,过度使用元组访问器应该被视为推动元组到案例类的推动。请考虑以下事项:
val name = ("Travis", "Brown")
println("Hello, " + name._1)
相反:
case class Name(first: String, last: String)
val name = Name("Travis", "Brown")
println("Hello, " + name.first)
第二个版本中的额外案例类定义为单行代码购买了大量可读性。
答案 1 :(得分:19)
有一个更好的解决方案x._N
。使用元组的常用方法是模式匹配:
charsListMap.map{case (a, b) => (a, b.length)}
你也可以看看scalaz
,元组有instruments个:
import scalaz._
import Scalaz._
scala> (1, "a") bimap (_ + 2, _ + 2)
res0: (Int, java.lang.String) = (3,a2)
scala> ('s, "abc") :-> { _.length }
res1: (Symbol, Int) = ('s,3)
答案 2 :(得分:1)
随着即将推出的Scala 3
(Dotty)和parameter untupling功能,以下将成为.map(x => x._1 -> x._2.length)
的替代选择:
.map(_ -> _.length)
因此,您的示例变为:
"test".toList.groupBy(identity).map(_ -> _.length).toList.sortBy(identity)
// List(("e", 1), ("s", 1), ("t", 2))
关于示例,更具体地讲,以Scala 2.13
开头,您还可以使用groupMapReduce,其名称(如其名称所示)等效于groupBy
,后跟mapValues
和减少步骤:
"test".groupMapReduce(identity)(_ => 1)(_ + _).toList.sortBy(identity)