【问题标题】:Zip sparse sequencesZip 稀疏序列
【发布时间】:2016-04-05 20:44:58
【问题描述】:

我有两个对象序列,其中对象共享一个公共属性(我们称之为 id)

case class ThingA(id: Int, someAttribute: String)
case class ThingB(id: Int, someOtherAttribute: Float)

我想加入“稀疏”列表,也就是说每个ThingA.id 可能不匹配ThingB.id,反之亦然。每个列表中的 id 都是唯一的。

示例输入:

val thingAs = Seq(ThingA(0, "foo"), ThingA(1, "bar"))
val thingBs = Seq(ThingB(0, 1.0), ThingB(2, 0.3))

期望的输出:

val zipped: Seq(Tuple[Option[ThingA], Option[ThingB]]) = Seq(
    (Some(ThingA(0, "foo")), Some(ThingB(0, 1.0))),   // Matching id = 0
    (Some(ThingA(1, "bar")), None),
    (None, Some(ThingB(2, 0.3))
)

我目前的尝试是这样的:

val zipped = (
    thingAs.map(a => (Some(a), thingBs.find(b => b.id == a.id))) ++
    thingBs.map(b => (thingAs.find(a => a.id == b.id), Some(b)))
).distinct

这行得通,但我希望有更好的方法。

【问题讨论】:

  • 查看.groupBy。按 id 分组一个 seq,然后 map 另一个加入。
  • @Dima,.groupBy 没有意义? " id 在每个列表中都是唯一的。"
  • @ArchetypalPaul 重点是Map 中的查找是恒定时间
  • 对,但是groupBy不需要把它变成Map。

标签: scala


【解决方案1】:

一种方法是首先计算所有 id 的并集,然后按照 @Dima 的建议使用查找图获取相应的 ThingAThingB 实例。

val lookupThingA = thingAs.map(x => x.id -> x).toMap
val lookupThingB = thingBs.map(x => x.id -> x).toMap

val zipped: Seq[(Option[ThingA], Option[ThingB])] =
    (lookupThingA.keySet | lookupThingB.keySet).map(i => (lookupThingA.get(i), lookupThingB.get(i))).toList

输出(请注意,您可以使用Set 而不是Seq):

(Some(ThingA(1,bar)),None)
(Some(ThingA(0,foo)),Some(ThingB(0,1.0)))
(None,Some(ThingB(2,0.3)))

(如果有人想改进它,我将它作为一个社区 wiki)

【讨论】:

  • 其实groupBy在这里并不是最合适的。 .map(x => x.id -> x).toMap 更好,因为您不会将值包装在集合中。
猜你喜欢
  • 2015-12-05
  • 1970-01-01
  • 2019-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多