Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使下面的scala不可变_Scala_Functional Programming_Immutability - Fatal编程技术网

如何使下面的scala不可变

如何使下面的scala不可变,scala,functional-programming,immutability,Scala,Functional Programming,Immutability,假设我有以下代码: BroadcastMessage以迭代器的形式获取只能遍历一次的学生组列表 呼叫sendMessage时,它将向小组中的所有学生发送消息 class BroadcastMessage(message:String,groups:List[Iterator[Student]]) { def sendMessage:Unit = { groups.foreach(group=>group.foreach(sendeMessage)) } priv

假设我有以下代码:

BroadcastMessage以迭代器的形式获取只能遍历一次的学生组列表 呼叫
sendMessage
时,它将向小组中的所有学生发送消息

class BroadcastMessage(message:String,groups:List[Iterator[Student]]) {

  def sendMessage:Unit = {
      groups.foreach(group=>group.foreach(sendeMessage))
  }

  private def sendMessage(student:Student): Unit ={
    EmailClient.sendMessage(student.email,message)
  }

}

case class Student(id: String,email:String)
假设学生可以分成几个小组,我们不想给他发送多封电子邮件

可变解决方案是添加可变集合,将学生的id添加到集合中,并且仅在集合中存在id时发送消息

class BroadcastMessage(message:String,groups:List[Iterator[Student]]) {
  // evil mutable set
  private var set:scala.collection.mutable.Set[String] = Set()

  def sendMessage:Unit = {
      groups.foreach(group=>group.foreach(sendeMessage))
  }

  private def sendMessage(student:Student): Unit ={
    if (set.add(student.id)) {
      EmailClient.sendMessage(student.email, message)
    }
  }

}

如何以不可变的方式实现它?

如果没有内存限制,您可以这样做:

def sendMessage:Unit = {
    groups.flatten.distinct.foreach(sendMessage)
}

如果没有内存限制,可以执行以下操作:

def sendMessage:Unit = {
    groups.flatten.distinct.foreach(sendMessage)
}

我认为在你的例子中,你在做两个不同的可变的东西,而你实际上只需要一个

您需要一个
private-var-set:mutable.set[Student]=mutable.set.empty[Student]
或一个
private-var-set:set[Student]=set.empty[Student]
。也就是说,您需要对集合本身进行变异,或者只对类持有的集合进行引用。我个人倾向于后者,结果是:

case class Student(id: String,email:String)

class BroadcastMessage(message:String,groups:List[Iterator[Student]]) {
  private var set : Set[Student] = Set.empty // <- no mutable Set, just a mutable reference to several immutable Sets

  def sendMessage:Unit = {
    groups.foreach(group=>group.foreach(sendMessage))
  }

  private def sendMessage(student:Student): Unit = {
    if (!set(student)) {
      set = set + student
      EmailClient.sendMessage(student.email, message)
    }
  }
}

我想这取决于风格…

好吧,我认为你在你的例子中创造了两种不同的可变事物,而你实际上只需要一种

您需要一个
private-var-set:mutable.set[Student]=mutable.set.empty[Student]
或一个
private-var-set:set[Student]=set.empty[Student]
。也就是说,您需要对集合本身进行变异,或者只对类持有的集合进行引用。我个人倾向于后者,结果是:

case class Student(id: String,email:String)

class BroadcastMessage(message:String,groups:List[Iterator[Student]]) {
  private var set : Set[Student] = Set.empty // <- no mutable Set, just a mutable reference to several immutable Sets

  def sendMessage:Unit = {
    groups.foreach(group=>group.foreach(sendMessage))
  }

  private def sendMessage(student:Student): Unit = {
    if (!set(student)) {
      set = set + student
      EmailClient.sendMessage(student.email, message)
    }
  }
}

我想这取决于当时的风格…

我设法做到了这一点。我想我失去了一些可读性,但它是可变的:

class BroadcastMessage(message: String, groups: List[Iterator[Student]]) {

  def sendMessage(): Unit = {
    groups.foldLeft[Set[String]](Set.empty)(sendMessage)
  }

  private def sendMessage(sent: Set[String], group: Iterator[Student]):Set[String] = {
    group.foldLeft[Set[String]](sent)(sendMessage)
  }

  private def sendMessage(sent: Set[String], student: Student): Set[String] = {
    if (!sent.contains(student.id)) {
      EmailClient.sendMessage(student.email, message)
      return sent + student.id
    }
    sent
  }

}

我设法做到了这一点。我想我失去了一些可读性,但它是可变的:

class BroadcastMessage(message: String, groups: List[Iterator[Student]]) {

  def sendMessage(): Unit = {
    groups.foldLeft[Set[String]](Set.empty)(sendMessage)
  }

  private def sendMessage(sent: Set[String], group: Iterator[Student]):Set[String] = {
    group.foldLeft[Set[String]](sent)(sendMessage)
  }

  private def sendMessage(sent: Set[String], student: Student): Set[String] = {
    if (!sent.contains(student.id)) {
      EmailClient.sendMessage(student.email, message)
      return sent + student.id
    }
    sent
  }

}

您可以使用一个班轮:

def发送消息:单位=
groups.reduce(++).toStream.distinct.foreach(sendMessage)

学习用扩展版:

val学生:迭代器[Student]=组。减少(++)
val sstudens:Stream[学生]=students.toStream
val dStudents:Stream[Student]=sstudens.distinct
def sendMessage:Unit=sStudents.foreach(sendMessage)

您可以使用一行程序:

def发送消息:单位=
groups.reduce(++).toStream.distinct.foreach(sendMessage)

学习用扩展版:

val学生:迭代器[Student]=组。减少(++)
val sstudens:Stream[学生]=students.toStream
val dStudents:Stream[Student]=sstudens.distinct
def sendMessage:Unit=sStudents.foreach(sendMessage)

看起来您要查找的内容在嵌套集合中都是唯一的
Student
s

一个非常简单的方法是将集合展平并将其转换为
集合
;以下是
Int
s的示例:

scala> val groups = List(Iterator(1,2,3), Iterator(3,4,5))
groups: List[Iterator[Int]] = List(non-empty iterator, non-empty iterator)

scala> val unique: Set[Int] = groups.flatten.toSet
unique: Set[Int] = Set(5, 1, 2, 3, 4)
这里的一个问题是
toSet
方法实际上复制了您的列表。为了避免这种情况,您可以使用以下小技巧(您可以阅读更多关于
collection.breakOut
CanBuildFrom
):


然而,这里的易变性的来源是一个
迭代器的使用,它无论如何都会被使用,在那里会发生变异和破坏。

看起来你所寻找的是嵌套集合中唯一的
学生
s

一个非常简单的方法是将集合展平并将其转换为
集合
;以下是
Int
s的示例:

scala> val groups = List(Iterator(1,2,3), Iterator(3,4,5))
groups: List[Iterator[Int]] = List(non-empty iterator, non-empty iterator)

scala> val unique: Set[Int] = groups.flatten.toSet
unique: Set[Int] = Set(5, 1, 2, 3, 4)
这里的一个问题是
toSet
方法实际上复制了您的列表。为了避免这种情况,您可以使用以下小技巧(您可以阅读更多关于
collection.breakOut
CanBuildFrom
):


然而,这里的易变性的来源是使用一个
迭代器
,它无论如何都会被使用,会发生变异和破坏。

我认为OP希望这样,如果再次调用该方法,相同的
学生
不会被发送新消息。在本例中,我没有内存限制,但我的真实代码中有它。学生迭代器实际上是一个文件流。你可以使用流,它也有“distinct”操作,这样你就不会有任何内存问题。我认为OP希望这样,如果再次调用该方法,相同的
学生
不会被发送新消息。在本例中,我没有内存限制,但我的真实代码中有它。学生迭代器实际上是一个文件流。你可以使用流,它还有“独特”操作,这样你就不会有任何内存问题。你觉得我的解决方案怎么样?但我看到在你的秒解决方案中,你在每个项目上遍历两次。。。这是我做不到的。(我知道在这个例子中它看起来不错,但在我的真实代码中,学生迭代器实际上是文件读取器)。我认为它工作正常,但我认为您需要集合,因为如果您的方法被多次调用,您将不希望再次通知学生。如果是这种情况,那么您的解决方案就是将跟踪这种情况的责任委托给方法的调用方。如果你同意,那就太好了。:)我不认为我对迭代器进行了两次迭代……我确实对内部集合进行了两次检查,但每个迭代器只扫描一次,
student您有一个很好的观点。我希望我能让事情变得更无状态,尽管(没有
var
)。很好。你觉得我的解决方案怎么样?但我看到在你的秒解决方案中,你在每个项目上遍历两次。。。这是我做不到的。(我知道在这个例子中,它看起来还可以,但在我的实际代码中,学生迭代器实际上是文件读取器)。我认为它可以工作,但我认为您需要集合,因为如果您的方法被多次调用,您将