1

My Current Structure:

input:
[
   {A:A1, B:B1, C:C1, D:D1, E:E1, F:F1, G:G1, H:H1},
   {A:A2, B:B2, C:C2, D:D2, E:E2, F:F2, G:G2, H:H2},
   {A:A3, B:B3, C:C3, D:D3, E:E3, F:F3, G:G3, H:H3}
   ...
]

My Goal:

output
[
   {"A":[A1, A2, A3 ...]},
   {"B":[B1, B2, B3 ...]},
   {"C":[C1, C2, C3 ...]},
   {"D":[D1, D2, D3 ...]},
   {"E":[E1, E2, E3 ...]},
   {"F":[F1, F2, F3 ...]},
   {"G":[G1, G2, G3 ...]},
   {"H":[H1, H2, H3 ...]}
]

Where "A", "B", "C"... are the literal keys from the original objects, and they are now keys in an object to an array of all values of their type. This is usually simple except for the fact that I need to maintain the keys throughout

This is what I've tried so far but I'm not sure if my loop structure is correct.

def ArrayList invertReponse(ArrayList input){

    def output = new ArrayList()

    for(i=0;i<input[0].size();i++){ 

        def tempObj = {}
        def j=0
        input[0].each{ key, value ->            
            tempObj[[input][0][i]][j] = value
            j++
        }
        output.push(tempObj)
    }   
    return output
}
4
  • This sounds like a job for a Map. Is there a particular reason you have to use an list for this? Commented Oct 25, 2017 at 20:54
  • No reason other than the fact that the original structure is a list. I'll look into it Commented Oct 25, 2017 at 20:56
  • 1
    Seems to be Json data? Commented Oct 26, 2017 at 1:44
  • Since both answers are already pretty similar, one can "golf" this a little more by using .withDefault on the starting map. list.inject([:].withDefault{[]}){ m, it -> it.each{ k, v -> m.get(k).add(v)}; m } Commented Oct 26, 2017 at 10:49

2 Answers 2

1

Depending on the assumptions you can make about the input, you might want to start with something like this:

def input = [[A:'A1', B:'B1', C:'C1'],
             [A:'A2', B:'B2', C:'C2'],
             [A:'A3', B:'B3', C:'C3']]

def result = input.inject([:]) { map1, map2 ->
    (map1.keySet() + map2.keySet())
        .inject([:]) {m, k -> m[k] = (map1[k] ?: []) + (map2[k] ?: []); m}
}

result will end up being [A:[A1, A2, A3], B:[B1, B2, B3], C:[C1, C2, C3]].

I hope that helps.

EDIT:

After re-reading the question I see now that what you really want as a result is a List that contains a bunch of Map that each have just 1 key in them. This may be closer to what you want...

def input = [[A:'A1', B:'B1', C:'C1'],
             [A:'A2', B:'B2', C:'C2'],
             [A:'A3', B:'B3', C:'C3']]

def result = []
input.inject([:]) { map1, map2 ->
    (map1.keySet() + map2.keySet())
        .inject([:]) {m, k -> m[k] = (map1[k] ?: []) + (map2[k] ?: []); m}
}.each { k, v ->
    result << [(k):v]
}

With that, result will be [[A:[A1, A2, A3]], [B:[B1, B2, B3]], [C:[C1, C2, C3]]].

Sign up to request clarification or add additional context in comments.

2 Comments

This is exactly what I was looking for. What if we assume the input is non-rectangular (ie some fields may be null), it is possible to identify those and insert "null" or "0" where missing?
Yes, you could do whatever kind of mapping you like. For example, you could represent null with the literal String "null", or the number zero or the String "0" or whatever you like.
1

Another way would be to leverage the power of higher order functions as:

def list = [
   [A:'A1', B:'B1', C:'C1', D:'D1', E:'E1', F:'F1', G:'G1', H:'H1'],
   [A:'A2', B:'B2', C:'C2', D:'D2', E:'E2', F:'F2', G:'G2', H:'H2'],
   [A:'A3', B:'B3', C:'C3', D:'D3', E:'E3', F:'F3', G:'G3', H:'H3']
]

// Flexibility on merge condition by provding a Closure
Map mergeOn(Map one, Map two, Closure closure) {
  two.inject([:] << one) { acc, key, val ->
    key in acc.keySet() ? acc[key] = closure(acc[key], val) : acc << [(key): val]
    acc
  }
}

assert list.inject { acc, item -> 
  mergeOn(acc, item) { a, b -> 
    a instanceof List ? a << b : [a, b] 
  } 
}.collect { k, v -> [(k) : v] } == [
   [A: ['A1', 'A2', 'A3']],
   [B: ['B1', 'B2', 'B3']],
   [C: ['C1', 'C2', 'C3']],
   [D: ['D1', 'D2', 'D3']],
   [E: ['E1', 'E2', 'E3']],
   [F: ['F1', 'F2', 'F3']],
   [G: ['G1', 'G2', 'G3']],
   [H: ['H1', 'H2', 'H3']]
]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.