如何配对两个排序列表中的类似对象?

时间:2013-02-02 17:33:39

标签: scala list

我正在尝试学习Scala(2.10)。在本练习中,我有一个案例类:

case class Entry(name: String, version: String) { }

我有两个这样的对象序列,按名称属性排序:

S1 = E1, E3, E4
S2 = F1, F2, F4

我想构建一个新序列:

S3 = (E1, F1), (None, F2), (E3, None), (E4, F4)

按名称属性对其进行配对,最好不必在每个列表上多次迭代。

我对这个问题的所有解决方案都变得非常迫切(例如,有条件地增加两个整数并使用.get())。我希望某种善良的灵魂可以提出更具功能性的方法。

3 个答案:

答案 0 :(得分:4)

您的意思是version属性,从示例来看?

您可以使用列表和递归:

def pair(s1: List[Entry], s2: List[Entry]): List[(Option[Entry], Option[Entry])] =
  (s1, s2) match {
    case (Entry(_, v1) :: _, Entry(_, v2) :: _) if v1 == v2 =>
      (Some(s1.head), Some(s2.head)) :: pair(s1.tail, s2.tail)
    case (Entry(_, v1) :: s1t, Entry(_, v2) :: s2t) =>
      if (v1 < v2) (Some(s1.head), None) :: pair(s1.tail, s2)
      else (None, Some(s2.head)) :: pair(s1, s2.tail)
    case (Nil, s2) => s2.map(entry => (None, Some(entry))
    case (s1, Nil) => s1.map(entry => (Some(entry), None)
  }

基本上,你进入列表比较他们的头部,如果版本相同,则采取两个头,或者只采用较小的头部。然后递归地对列表的尾部执行相同的操作。如果其中一个列表为空,则只需将另一个列表的其余元素映射为None和条目对。

答案 1 :(得分:0)

如果我理解正确,EX表示name="E"version="X",您希望将相同版本的内容配对。这是我的解决方案,不幸的是需要平时,所以如果效率很重要,请不要使用它......

val versions = (S1 ++ S2) map { _.version } groupBy (identity) keys
val sortedVersions = versions.toSeq.sorted
sortedVersions map { ver => (S1 find { _.version==ver }, S2 find { _.version==ver }) }

或者如果您事先知道可能的版本是什么,只需制作一个序列并执行最后一行。

Seq("1", "2", "3", "4") map { ver => (S1 find { _.version==ver }, S2 find { _.version==ver }) }

结果:

 ArrayBuffer((Some(Entry(E,1)),Some(Entry(F,1))), (None,Some(Entry(F,2))), (Some(Entry(E,3)),None), (Some(Entry(E,4)),Some(Entry(F,4))))

请注意,我(None, F2)代替(None, Some(F2)),而NoneSome配对似乎更加一致。

BTW,case class(...)就足够了,您无需在其后面添加空括号{ }

答案 2 :(得分:0)

我无法在我的ipad上显示详细信息;)但是如果数字中没有很多间隙,您可以扫描每个列表,通过构建新列表或向量在空白处插入Nones(向量更快)使用像axel22这样的递归算法显示,然后将集合压缩在一起。