1

I have 2 immutable case classes A(source, key, value) and B(source, key, value) I want to add A over B in such a way when 'source' and 'key' doesn't exist, to be added from A to the B and when 'source' and 'key' exist to replace the value from B with the one from A. The same way 'merge_array' function from php works on a multidimensional array.

I tried with 'A.union(B).groupBy(.key)' and then 'groupBy(.source)' and get the 1st value. But then I realized that I can never be sure that first value will always be the value of A.

I'm quite new to scala and I really ran out of ideas how I could do this from a functional immutable point of view.

Anyone has any idea how I could do this?

Thank you

Edit:

case class TranslationValue(source: String, key: String, value: String)

def main(args:Array[String]):Unit = {
    println(merge(data1.toSet, data2.toSet))
}

def merge(a: Set[TranslationValue], b: Set[TranslationValue]) = {
    a.union(b).groupBy(_.key).flatMap{ case (s, v) =>
       v.groupBy(_.source).flatMap{case (s1, v1) => {
         for (res <- 0 to 0) yield v1.head
       }
    }
  }
}

Example

data1 has this data

Set(
 TranslationValue(messages,No,No),
 TranslationValue(messages,OrdRef,Order Reference),
 TranslationValue(messages,OrdId,Order Id)
)

data2 has this data

Set(
 TranslationValue(messages,No,No),
 TranslationValue(messages,OrdRef,OrderRef)
 TranslationValue(messages,Name,Name)
)

putting data1 over data2 I want to obtain

List(
 TranslationValue(messages,No,No),
 TranslationValue(messages,OrdRef,Order Reference),
 TranslationValue(messages,OrdId,Order Id)
 TranslationValue(messages,Name,Name)
)

I know that what I do can be done better, but like I said, I'm learning :)

user2035693
  • 193
  • 2
  • 16
  • 2
    A case class doesn't have union. What's really the type of A? – Christian Jun 18 '14 at 15:20
  • 2
    Can you please show some actual code? We need to see types, function definitions, examples of input/expected output... – vptheron Jun 18 '14 at 15:20
  • +1, this is a good question, but as others have pointed out, you need to add some detail. – Travis Brown Jun 18 '14 at 15:23
  • Is it on purpose that your return type is `List[A]` (as per your last example) instead of `Set[A]`? Why wouldn't you to stick to a `Set[A]`? – vptheron Jun 18 '14 at 17:18
  • from here the result will be printed in a file so the fact that is returning a List[A] is not a problem at all. I'm just using Set[A] so I can do union and groupBy. But I'm not sure that this way value of A will always override the value of B in 100% of the cases. So if you have a better idea how I can do it, I'm very thankful :) – user2035693 Jun 19 '14 at 08:31

1 Answers1

2

you can group in one go:

def merge(a: Seq[TranslationValue], b: Seq[TranslationValue]) = {
  a.union(b).groupBy(t=>(t.key,t.source)).map(c=>c._2.head)
}

i think you could also override the equals method for TranslationValue so that two translation values are equal when source and key are the same(the hashcode method has also to be overridden). Then a.union(b) would be enough.

edit:
It seems Set doesnt guarantee order of items(Scala: Can I rely on the order of items in a Set?), but a seq should.

Community
  • 1
  • 1
Siphor
  • 2,522
  • 2
  • 13
  • 10
  • Thank you. That's way nicer. But are you sure that this way the value of 'a' will always "override" the value of 'b' when 'key' and 'source' match? By doing union and then groupBy, there aren't chances that value of 'a' will come second, value of 'b' first and instead of getting the value of 'a' instead we get the value of 'b'? – user2035693 Jun 19 '14 at 08:23