12

从电子邮件列表中,我必须获得 2 个值:

  • 列表头的选项
  • 其余名单

在 scala 中编写此代码的惯用方式是什么?到目前为止,我有:

val primaryEmail = emails.headOption
val conf = Map[String, Any](
  "email" -> primaryEmail,
  "additionalEmails" -> 
     primaryEmail.map(_ => emails.tail).getOrElse(List())
)

编辑:至于为什么存在Any:我们使用 GSON 进行 json 序列化,并在内部将所有集合转换为 java 集合并将它们传递给jsonSerializationContext.serialize,它以 java.lang.Object 作为参数,所以很Any适合我们。

4

5 回答 5

21

我可能只是drop第一个元素(如果您确定第一个元素始终是主要电子邮件)。像这样:

val conf = Map[String, Any](
  "email" -> emails.headOption,
  "additionalEmails" -> emails.drop(1)
)

如果主电子邮件不在列表中(列表为空),这不会给出异常。

于 2013-06-18T15:20:08.873 回答
8

教你一个scalaz。所有这些都可以在一个电话中获得:

val (primary, rest) =  list <^> (nel => some(nel.head) -> nel.tail)
val conf = Map("email" -> primary, "additionalEmails" -> rest)

示范:

scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)

如果非空

scala> val (primary, rest) =  list <^> (nel => some(nel.head) -> nel.tail)
primary: Option[Int] = Some(1)
rest: List[Int] = List(2, 3)

如果为空:

scala> val list = List.empty[Int]
list: List[Int] = List()

scala> val (primary, rest) =  list <^> (nel => some(nel.head) -> nel.tail)
primary: Option[Int] = None
rest: List[Int] = List()

这是如何运作的?

<^>调用说:如果此列表为空,则返回由右侧返回类型函数定义的类型零。如果列表不为空,则将函数应用于它

nel是 a NonEmptyList,我可以安全地调用它,headtail不用担心它们会抛出异常。我的函数返回一个(Option[A], List[A])

当然,这个(None, Nil)适用于任何A

于 2013-06-18T16:29:21.790 回答
2

对于序列,您可以对它们进行模式匹配以获得头部和其余部分

val lst1 = Seq("primary", "secondary", "other");
// ...
lst1 match {
  case Seq(primary, rest @ _*)  => println(primary + "/" + rest);
  case _                        => println("Error: list empty.");
}

如果你使用 Scala 的Lists,那就更好了:

val lst2 = List("primary", "secondary", "other");
// ...
lst2 match {
  case primary :: rest  => println(primary + "/" + rest);
  case Nil              => println("Error: list empty.");
}

另请参阅模式匹配序列理解的惯用方式是什么?Lists 以外的序列上的 Scala 模式匹配


就像鲁本一样,我强烈建议您不要使用Map[String,Any]或类似的结构。您正在丢弃 Scala 类型系统为您提供的所有内容。很容易得到难以追踪的错误。也许将其作为另一个问题提出 - 描述您Map[String,Any]现在使用的原因并询问如何改进它。

于 2013-06-18T18:58:01.623 回答
1

地图[字符串,任何]?你不妨只写 PHP ... ;-)

这是另一种方式:

scala> def build( emails:Seq[String] ):Map[String,Any] =
 emails.headOption.map(
         (primary) => Map( "primary" -> Some(primary), "other" -> emails.tail )
   ).getOrElse( Map( "primary" -> None, "other" -> Nil ) )
build: (emails: Seq[String])Map[String,Any]

scala> build(Nil)
res2: Map[String,Any] = Map(primary -> None, other -> List())

scala> build( List("fred"))
res3: Map[String,Any] = Map(primary -> Some(fred), other -> List())

真的 - 我不喜欢整个方法 - 我会做这样的事情:

case class EmailTo( primary:String, other:Seq[String] );

object EmailTo {
    def apply( addrs:Seq[String] ):Option[EmailTo] = 
         addrs.headOption.map( (primary) => EmailTo( primary, addrs.tail ) )
}
于 2013-06-18T18:16:00.243 回答
0

我建议

(("email", "additionalEmail") zip emails.splitAt(1)).toMap

这将第一封电子邮件留在 a Listnot anOption中,但 aMap[String, Product]无论如何都不会对您有太大帮助,是吗?

于 2013-06-18T17:25:56.327 回答