2016-04-05 5 views
1

У меня есть две последовательности объектов, где объекты имеют общий атрибут (назовём его идентификатор)Zip редкие последовательности

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

Я хочу присоединиться к «разреженные» списков, который должен сказать, что каждый ThingA.id мощь не соответствуют ThingB.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 

, который работает, но я надеюсь, что там это лучший способ.

+0

Посмотрите в ' .groupBy'. Группируйте один раз по id, затем «сопоставьте» другой, чтобы присоединиться. – Dima

+2

@ Дима, нет точки в '.groupBy'? «Иды уникальны в каждом списке». –

+0

@ArchetypalPaul точка поиска в «Карте» постоянное время – Dima

ответ

2

Один из способов - сначала вычислить объединение всех идентификаторов, а затем получить соответствующие экземпляры или ThingB с использованием карт поиска, как предположил @Dima.

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 

Output (обратите внимание, что вы можете иметь Set вместо Seq):

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

(я позволяю это как сообщества вики, если кто-то хочет, чтобы улучшить это)

+0

На самом деле 'groupBy' здесь не подходит. '.map (x => x.id -> x) .toMap' лучше, так как вы не переносите значения в коллекции. – Aivean

+0

@Aivean Действительно, спасибо :) –

Смежные вопросы