【问题标题】:How to make a nested toSet in scala in an idiomatic way?如何以惯用的方式在scala中制作嵌套的toSet?
【发布时间】:2014-03-09 10:25:39
【问题描述】:

有没有更惯用的方法将嵌套的序列序列更改为嵌套的集合集?

def toNestedSet[T](tsss: Seq[Seq[Seq[T]]]): Set[Set[Set[T]]]  = 
   tsss.map(_.map(_.toSet).toSet).toSet

是否有可能实现一个适用于任何深度列表的函数?

【问题讨论】:

  • 绝对可以以类型安全的方式执行此操作,无需任何Any 或强制转换——例如,请参阅my answer here 以获得类似问题的解决方案。你的问题有点复杂,但我 100% 确定这种方法会奏效。
  • 我的第一个想法是“也许Shapeless可以处理任意嵌套Seq to Set的一般问题?” (github.com/milessabin/shapeless)
  • 当我发现自己处于这种情况时,我通常会为一个或多个内部嵌套定义一个类型定义,无论如何我都需要大量重用。
  • @RandallSchulz:我想不出有什么方法可以让 Shapeless 比无 Shapeless 的实现更容易(比如 mine below)。不过,也许我错了——例如可能有一些方法可以让 SYB 做到这一点,而我目前还没有看到。

标签: list scala set nested seq


【解决方案1】:

这实际上并不算太糟糕(请参阅my answer here 到类似问题以了解有关此方法的一些额外讨论):

trait Setsifier[I, O] { def apply(i: I): O }

object Setsifier {
  def apply[I, O](f: I => O) = new Setsifier[I, O] { def apply(i: I) = f(i) }

  implicit def base[I](implicit ev: I <:!< Seq[_]) = apply((_: Seq[I]).toSet)

  implicit def rec[I, O](implicit s: Setsifier[I, O]) =
    apply((_: Seq[I]).map(s(_)).toSet)
}

def setsify[I, O](i: I)(implicit s: Setsifier[I, O]) = s(i)

然后:

scala> println(setsify(Seq(Seq(Seq(Seq(1)), Seq(Seq(2, 3))))))
Set(Set(Set(Set(1)), Set(Set(2, 3))))

静态类型为Set[Set[Set[Set[[Int]]]] 等。

好吧,我撒了一点谎。上面的&lt;:!&lt; 实际上不在标准库中。不过,它位于 Shapeless 中,或者您可以非常非常轻松地自己定义它:

trait <:!<[A, B]

implicit def nsub[A, B] : A <:!< B = new <:!<[A, B] {}
implicit def nsubAmbig1[A, B >: A] : A <:!< B = sys.error("Don't call this!")
implicit def nsubAmbig2[A, B >: A] : A <:!< B = sys.error("Don't call this!")

仅此而已。

【讨论】:

  • 嗯,这很聪明。我在工作中遇到了一个问题,涉及比我目前使用下面答案的更复杂变体处理的 OP 更复杂的递归数据结构(我从来没有真正满意过)。我可能会尝试适应这个:)
  • 一个脚注:为了清楚起见,我在这里忽略了差异问题,这意味着此版本仅在您的序列静态类型为 Seq 时才有效。 “解决”这个问题并不难——只是有点混乱。
  • 您好,我喜欢这两个答案,但 James Adam 提供的答案解决了问题并且仍然很简单。所以我接受了他的回答。然而,对于高级应用程序和用户来说,您的答案可能更方便。 +1
  • @goozez:很公平,但我只想指出,丢失类型信息意味着您必须转换结果,这消除了任意实现此功能的大部分优势马上筑巢。
  • @TravisBrown nsubAmbig2 有错误吗?它看起来和 nsubAmbig1 完全一样。
【解决方案2】:

要解决您问题的第二部分(处理任意深度的列表),可以使用类似这样的方法(类型擦除有点碍事):

  def toNestedSet(ts: Seq[Any]): Set[Any] = {
    ts.foldLeft[Set[Any]](Set())((acc, b) => b match {
        case s: Seq[_] => acc + toNestedSet(s)
        case x => acc + x
    })
  } 

注意:又快又脏——它可以工作,但很容易破解:)

编辑:演员阵容是多余的

【讨论】:

  • 我其实更喜欢 op 的解决方案 :)
  • Op 的解决方案不适用于任意深度的 Seq。如果深度是已知的,那么是的 - 这就是要走的路。
  • 我不会说类型擦除“妨碍了”,而是说“类型擦除使在模式匹配中的类型调度几乎与应有的一样令人不快”。
猜你喜欢
  • 1970-01-01
  • 2020-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多