2011-01-06 8 views
3

Ich möchte eine Karte in ein Array von Karten aufteilen. Zum Beispiel, wenn es eine Karte mit 25 Schlüssel/Wert-Paaren gibt. Ich möchte eine Reihe von Karten mit nicht mehr als 10 Elementen in jeder Karte.Teilen Sie eine Karte mit Groovy

Wie würde ich das in groovy tun?

ich eine Lösung, die ich über nicht aufgeregt bin, ist es besser, groovy Version:

static def splitMap(m, count){ 
    if (!m) return 

    def keys = m.keySet().toList() 
    def result = [] 
    def num = Math.ceil(m?.size()/count) 
    (1..num).each { 
     def min = (it - 1) * count 
     def max = it * count > keys.size() ? keys.size() - 1 : it * count - 1 
     result[it - 1] = [:] 
     keys[min..max].each {k -> 
     result[it - 1][k] = m[k] 
     } 
    } 
    result 
    } 

m die Karte ist. Anzahl ist die maximale Anzahl der Elemente in der Karte.

Antwort

6

Adapting my answer to this question on partitioning a List, kam ich mit dieser Methode auf:

Map.metaClass.partition = { size -> 
    def rslt = delegate.inject([ [:] ]) { ret, elem -> 
    (ret.last() << elem).size() >= size ? ret << [:] : ret 
    } 
    rslt.last() ? rslt : rslt[ 0..-2 ] 
} 

Also, wenn Sie diese Karte nehmen:

def origMap = [1:'a', 2:'b', 3:'c', 4:'d', 5:'e', 6:'f'] 

Alle folgenden Behauptungen passieren :-)

assert [ [1:'a'], [2:'b'], [3:'c'], [4:'d'], [5:'e'], [6:'f'] ] == origMap.partition(1) 
assert [ [1:'a', 2:'b'], [3:'c', 4:'d'], [5:'e', 6:'f'] ]  == origMap.partition(2) 
assert [ [1:'a', 2:'b', 3:'c'], [4:'d', 5:'e', 6:'f'] ]   == origMap.partition(3) 
assert [ [1:'a', 2:'b', 3:'c', 4:'d'], [5:'e', 6:'f'] ]   == origMap.partition(4) 
assert [ [1:'a', 2:'b', 3:'c', 4:'d', 5:'e'], [6:'f'] ]   == origMap.partition(5) 
assert [ [1:'a', 2:'b', 3:'c', 4:'d', 5:'e', 6:'f'] ]   == origMap.partition(6) 

Oder als Category (Um zu vermeiden, etwas zu dem metaClass von Map hinzufügen zu müssen:

class MapPartition { 
    static List partition(Map delegate, int size) { 
    def rslt = delegate.inject([ [:] ]) { ret, elem -> 
     (ret.last() << elem).size() >= size ? ret << [:] : ret 
    } 
    rslt.last() ? rslt : rslt[ 0..-2 ] 
    } 
} 

Dann, in dem Sie diese Funktion benötigen, können Sie einfach use die Kategorie wie folgt:

use(MapPartition) { 
    assert [ [1:'a'], [2:'b'], [3:'c'], [4:'d'], [5:'e'], [6:'f'] ] == origMap.partition(1) 
    assert [ [1:'a', 2:'b'], [3:'c', 4:'d'], [5:'e', 6:'f'] ]  == origMap.partition(2) 
    assert [ [1:'a', 2:'b', 3:'c'], [4:'d', 5:'e', 6:'f'] ]   == origMap.partition(3) 
    assert [ [1:'a', 2:'b', 3:'c', 4:'d'], [5:'e', 6:'f'] ]   == origMap.partition(4) 
    assert [ [1:'a', 2:'b', 3:'c', 4:'d', 5:'e'], [6:'f'] ]   == origMap.partition(5) 
    assert [ [1:'a', 2:'b', 3:'c', 4:'d', 5:'e', 6:'f'] ]   == origMap.partition(6) 
} 
+0

cool. Ich habe eine Grails-App. Wo setze ich den Map.metaClass.partition Code? Wird es beim Start aufgerufen? – Tihom

+0

setzen Sie es in BootStrap.init –

+0

@Tihom @Gareth oder, wenn Sie nicht mögen, die metaClass zu verschmutzen (was Dinge auch schwer testen lassen kann), habe ich meine Antwort geändert, um zu zeigen, wie man dasselbe macht wie eine Kategorie –

Verwandte Themen