Scott Presnell
Scott Presnell

Reputation: 1538

Merging lists of lists retaining order with groovy

I have two long lists of lists:

first = [[A, 2, 4, 6], [B, 1, 3, 5]...]
second = [[A, 8, 10, 12], [B, 7, 9, 11]...]

That would like to merge into (order retained)

first = [[A, 2, 4, 6, 8, 10, 12], [B, 1, 3, 5, 7, 9, 11]...]

(I'll be doing this inside an each{} of 'second' like results from a function call, so I need to keep merging into 'first') I think I'm looking for some kind of addition, plus flattening, but I can't quite get it. Any help would be appreciated.

Thanks!

Upvotes: 1

Views: 1261

Answers (3)

tim_yates
tim_yates

Reputation: 171074

If:

  • the lists are always matched so that if there is one 'A' record in first there is one in second, and if there's a 'B' record in first, there's one in second, etc
  • The lists are ordered in the same order

Then you can get away with:

[ first, second ].transpose()*.flatten()*.unique()

Upvotes: 4

Michael Easter
Michael Easter

Reputation: 24468

Consider this solution, though it is somewhat brittle (e.g. when keys do not align). Also, this modifies the 'first' list as a side-effect, which is a bit of a smell.

// modifies 'first' as a side-effect
def merge = { def first, def subSecond ->
    def subFirst = first.find { it[0] == subSecond[0] }
    if (subFirst) {
        subFirst.addAll( subSecond[1..subSecond.size()-1] )
    }
}

// tests 

def first = null
def results = null

first = [["A",2,4,6],["B",1,3,5]]
results = []
results.each { def subSecond -> merge(first,subSecond) }
assert [["A",2,4,6],["B",1,3,5]] == first

first = [["A",2,4,6],["B",1,3,5]]
results = [ ["A",8,10,12] ]
results.each { def subSecond -> merge(first,subSecond) }
assert [["A",2,4,6,8,10,12],["B",1,3,5]] == first

first = [["A",2,4,6],["B",1,3,5]]
results = [ ["A",8,10,12],["B",7,9,11]  ]
results.each { def subSecond -> merge(first,subSecond) }
assert [["A",2,4,6,8,10,12],["B",1,3,5,7,9,11]] == first

Upvotes: 0

Emil Sit
Emil Sit

Reputation: 23542

Here's one way to do it:

def merge(a, b) {
  tmp = b.collectEntries { [it.first(), it.tail()] }
  return a.collect { it + tmp[it.first()] }
}

It makes a temporary Map that is keyed by the first sub-entry of each entry in the second list, and then looks up the appropriate thing to append while iterating through the first list.

For example:

A = "A"
B = "B"
​first = [[A, 2, 4, 6], [B, 1, 3, 5]]
second = [[A, 8, 10, 12], [B, 7, 9, 11]]

println merge(first, second)

It could probably be made more robust to missing elements and such.

Upvotes: 3

Related Questions