在scala中连接包含在一组对象中的集合

在scala中连接包含在一组对象中的集合,scala,scala-collections,Scala,Scala Collections,我刚刚开始使用scala,我正在将一些java代码转换成scala,并试图使其美观、功能优雅 我有以下代码,其中包含一个方法(getRequiredUploadPathKeys),该方法提供MyClass中所有可用路径模板所需的所有路径键的并集 trait PathTemplate { def getRequiredPathKeys:Set[PathKey] } class MyClass(accessPaths:Set[PathTemplate], targetPath:PathTe

我刚刚开始使用scala,我正在将一些java代码转换成scala,并试图使其美观、功能优雅

我有以下代码,其中包含一个方法(getRequiredUploadPathKeys),该方法提供MyClass中所有可用路径模板所需的所有路径键的并集

trait PathTemplate {
    def getRequiredPathKeys:Set[PathKey]
}

class MyClass(accessPaths:Set[PathTemplate], targetPath:PathTemplate){

    def getAllRequiredPathKeys: Set[PathKey] = {
        val pathKeys = HashSet[PathKey]()
        pathKeys.addAll(targetPath.getRequiredPathKeys)

        for (accessTemp <- accessPaths) {
            pathKeys.addAll(accessTemp.getRequiredPathKeys)
        }
        return pathKeys
    }
}
trait路径模板{
def GetRequiredPathKey:设置[PathKey]
}
类MyClass(AccessPath:Set[PathTemplate],targetPath:PathTemplate){
def GetAllRequiredPathKey:设置[PathKey]={
val pathKeys=HashSet[PathKey]()
addAll(targetPath.getRequiredPathKeys)

对于(accessTemp您是指:

def getAllRequiredPathKeys = (accessPaths map { _.getRequiredPathKeys }).flatten ++ targetPath.getRequiredPathKeys
或与

def getAllRequiredPathKeys = 
  for(path <- accessPaths + targetPath; 
      key <- path.getRequiredPathKeys) yield key
def getAllRequiredPathKeys=

对于(path来说,这里的奇怪之处在于,您使用的是Java的
HashSet
——Scala中没有
addAll
——也不需要这样做

因此,我将对各种设计决策以及它们在Java和Scala之间的差异进行评论

    val pathKeys = HashSet[PathKey]()
惯用的Scala通常不引用实现接口的类,因为接口有一个工厂
。此外,这显然是一个Scala工厂,因为没有
new
关键字——这意味着其余的代码将无法工作,因为Scala的
集合中没有
addAll

    pathKeys.addAll(targetPath.getRequiredPathKeys)
这里您不直接使用
targetPath.getRequiredPathKeys
,因为Java的
Set
是可变的。默认的Scala
Set
是不可变的,这使得它毫无用处——您只需使用
targetPath.getRequiredPathKeys
作为基集,而不必将其元素添加到另一个集合中

就性能而言,Scala——与函数语言一样——在其不可变集合实现中使用。这意味着它重用一个数据结构的一部分来创建派生数据结构,而不是每次创建新数据结构时都复制所有内容。这只有在不可变性保证的情况下才可能实现

无论如何,您可以这样做:

val pathKeys = targetPath.getRequiredPathKeys
其次,

但是,请注意,
getRequiredPathKeys
的重复。函数式程序员讨厌重复。在我看来,有时候重复得太多了,但在这种情况下,它可以很容易地删除:

    val pathKeys = for {
        accessPath <- accessPaths + targetPath
        requiredPathKey <- accessPath.getRequiredPathKeys
    } yield requiredPathKey
末尾的
map
是多余的,因为它什么都不做。事实上,每当
yield
只返回一个简单标识符时,表达式中就有一个多余的
map
。删除它会给我们带来:

    val pathKeys = (accessPaths + targetPath).flatMap(accessPath =>
        accessPath.getRequiredPathKeys)
或者,使用Scala的匿名函数参数语法

    val pathKeys = (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
最后,

    return pathKeys
Scala中的关键字
return
用于指定工作流中的异常——在该点上,方法的执行被中止,而不是一直执行到结束。这并不是说它没有用处,而是像异常本身一样,它不应该无缘无故地被使用。在这里,您应该使用

    pathKeys
但是,此时,您的代码变成了这两行:

    val pathKeys = (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
    pathKeys
这使得
val
赋值完全冗余。因此,您可以将其减少为:

    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
因此,该方法成为

def getAllRequiredPathKeys: Set[PathKey] = {
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
}
现在,我知道我在后面说了“finally”,但还有一点Scala约定需要应用。每当一个方法包含一个表达式而不是多个语句时,约定是使用大括号。换句话说,执行以下操作:

def getAllRequiredPathKeys: Set[PathKey] =
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
或者,如果空间允许,将所有内容放在一行上。事实上,如果删除
getAllRequiredPathKeys
type,它将非常适合。另一方面,鼓励在public方法上使用显式返回类型

因此,这将为您提供一个Scala的不可变
。假设您的输入和输出必须是Java的
。在这种情况下,我看不到任何可以简化代码的方法,除非您愿意在Java和Scala集之间进行转换。您可以这样做:

trait PathTemplate {
    def getRequiredPathKeys:java.util.Set[PathKey]
}

import scala.collection.JavaConverters._

class MyClass(accessPaths:java.util.Set[PathTemplate], targetPath:PathTemplate){
    def getAllRequiredPathKeys: java.util.Set[PathKey] =
        (accessPaths.asScala + targetPath).flatMap(_.getRequiredPathKeys.asScala).asJava
}

但是,这使用了Scala的可变
,这意味着创建新
的每个操作都将复制旧
集的所有内容

您可以使用flatMap将其缩短。非常感谢:)我已经非常接近了,但是扁平化方法是缺少的一点!哇,这太神奇了。我仍然在消化所有的内容,但这是对解决方案演变的一个很好的描述。谢谢:)这是一个很好的演练,非常适合Java难民!谢谢!
    pathKeys.addAll(targetPath.getRequiredPathKeys)
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
def getAllRequiredPathKeys: Set[PathKey] = {
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
}
def getAllRequiredPathKeys: Set[PathKey] =
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
trait PathTemplate {
    def getRequiredPathKeys:java.util.Set[PathKey]
}

import scala.collection.JavaConverters._

class MyClass(accessPaths:java.util.Set[PathTemplate], targetPath:PathTemplate){
    def getAllRequiredPathKeys: java.util.Set[PathKey] =
        (accessPaths.asScala + targetPath).flatMap(_.getRequiredPathKeys.asScala).asJava
}