Groovy의 목록에서지도를 만드는 단축키?


106

나는 이것에 대해 약간의 정렬을 원합니다.

Map rowToMap(row) {
    def rowMap = [:];
    row.columns.each{ rowMap[it.name] = it.val }
    return rowMap;
}

GDK 물건이있는 방식을 고려하면 다음과 같은 작업을 수행 할 수있을 것으로 기대합니다.

Map rowToMap(row) {
    row.columns.collectMap{ [it.name,it.val] }
}

하지만 문서에서 아무것도 보지 못했습니다 ... 뭔가 빠졌나요? 아니면 내가 너무 게으른가요?


2
Amir의 의견은 이제 정답입니다. stackoverflow.com/a/4484958/27561
Robert Fischer

답변:


119

저는 최근에 정확히 목록을지도로 변환해야 할 필요성을 발견했습니다. 이 질문은 Groovy 버전 1.7.9가 나오기 전에 게시되었으므로 collectEntries아직 메서드 가 존재하지 않았습니다. 제안 된collectMap 방법 과 똑같이 작동합니다 .

Map rowToMap(row) {
    row.columns.collectEntries{[it.name, it.val]}
}

어떤 이유로 이전 Groovy 버전을 사용하는 경우이 inject방법을 사용할 수도 있습니다 ( 여기에 제안 된대로 ). 이것은 클로저 내부에 하나의 표현식 만 사용하는 약간 수정 된 버전입니다 (문자 저장을 위해!) :

Map rowToMap(row) {
    row.columns.inject([:]) {map, col -> map << [(col.name): col.val]}
}

+연산자도 대신 사용될 수있다 <<.


28

"주입"을 확인하십시오. 실제 함수형 프로그래밍은이를 "폴드"라고 부릅니다.

columns.inject([:]) { memo, entry ->
    memo[entry.name] = entry.val
    return memo
}

그리고 당신이 그것에있는 동안, 당신은 아마도 메타 클래스에서 오른쪽이 아닌 카테고리로 메소드를 정의하고 싶을 것입니다. 이렇게하면 모든 컬렉션에 대해 한 번 정의 할 수 있습니다.

class PropertyMapCategory {
    static Map mapProperty(Collection c, String keyParam, String valParam) {
        return c.inject([:]) { memo, entry ->
            memo[entry[keyParam]] = entry[valParam]
            return memo
        }
    }
}

사용 예 :

use(PropertyMapCategory) {
    println columns.mapProperty('name', 'val')
}

그루비에서는 inject : into : in Smalltalk : | 목록 합계 | list : = OrderedCollection 새 추가 : 1; 추가 : 2; 추가 : 3; 당신 자신. sum : = list inject : 0 into : [: a : b | a + b]. cr; 표시 : 합계. "prints 6"
OlliP

13

이 질문을 받았을 때 groupBy 메서드를 사용할 수 없었습니까 ?


아니요. 2011 년 1.8.1 이후입니다.이 질문은 2008 년에 제기되었습니다. 그러나 어쨌든 이제 groupBy는 실제로 갈 길입니다.
mvmn 2014

groupBy 문서에서 볼 수 있듯이 기본적으로 요소를 그룹으로 그룹화하며 각 그룹에는 특정 키와 일치하는 요소가 포함됩니다. 따라서 반환 유형은 Map<K, List<V>>OP가 반환 유형이 있는 메서드를 찾고있는 것 Map<K, V>같으므로이 경우 groupBy가 작동하지 않습니다.
Krzysiek Przygudzki 19.11. 06

6

필요한 것이 간단한 키-값 쌍 collectEntries이면 방법으로 충분합니다. 예를 들면

def names = ['Foo', 'Bar']
def firstAlphabetVsName = names.collectEntries {[it.charAt(0), it]} // [F:Foo, B:Bar]

그러나 키당 여러 값이있는 멀티 맵과 유사한 구조를 원한다면 groupBy방법 을 사용하고 싶을 것입니다.

def names = ['Foo', 'Bar', 'Fooey']
def firstAlphabetVsNames = names.groupBy { it.charAt(0) } // [F:[Foo, Fooey], B:[Bar]]


5

그래 ... 조금 더 해봤는데이게 꽤 멋진 방법 인 것 같아 ...

def collectMap = {Closure callback->
    def map = [:]
    delegate.each {
        def r = callback.call(it)
        map[r[0]] = r[1]
    }
    return map
}
ExpandoMetaClass.enableGlobally()
Collection.metaClass.collectMap = collectMap
Map.metaClass.collectMap = collectMap

이제 Map 또는 Collection의 모든 하위 클래스에이 메서드가 있습니다.

여기에서는 맵에서 키 / 값을 반전하는 데 사용합니다.

[1:2, 3:4].collectMap{[it.value, it.key]} == [2:1, 4:3]

여기에서는 목록에서지도를 만드는 데 사용합니다.

[1,2].collectMap{[it,it]} == [1:1, 2:2]

이제 내 앱이 시작될 때 호출되는 클래스에 이것을 팝하고이 메서드는 내 코드 전체에서 사용할 수 있습니다.

편집하다:

모든 배열에 메서드를 추가하려면 ...

Object[].metaClass.collectMap = collectMap

1

내장 된 항목을 찾을 수 없지만 ExpandoMetaClass를 사용하면 다음과 같이 할 수 있습니다.

ArrayList.metaClass.collectMap = {Closure callback->
    def map = [:]
    delegate.each {
        def r = callback.call(it)
        map[r[0]] = r[1]
    }
    return map
}

이것은 모든 ArrayLists에 collectMap 메소드를 추가합니다 ... List 또는 Collection에 추가하는 것이 작동하지 않는 이유를 잘 모르겠습니다. 다른 질문에 대한 것 같습니다 ...하지만 이제 할 수 있습니다 ...

assert ["foo":"oof", "42":"24", "bar":"rab"] ==
            ["foo", "42", "bar"].collectMap { return [it, it.reverse()] }

목록에서 계산 된지도까지 하나의 클로저로 ... 정확히 내가 찾던 것입니다.

편집 : 목록 및 컬렉션 인터페이스에 메서드를 추가 할 수없는 이유는 이렇게하지 않았기 때문입니다.

List.metaClass.enableGlobally()

메서드 호출 후 인터페이스에 메서드를 추가 할 수 있습니다.이 경우에는 내 collectMap 메서드가 다음과 같은 범위에서 작동 함을 의미합니다.

(0..2).collectMap{[it, it*2]}

지도를 생성합니다. [0 : 0, 1 : 2, 2 : 4]


0

이런 건 어때?

// setup
class Pair { 
    String k; 
    String v; 
    public Pair(def k, def v) { this.k = k ; this.v = v; }
}
def list = [ new Pair('a', 'b'), new Pair('c', 'd') ]

// the idea
def map = [:]
list.each{ it -> map.putAt(it.k, it.v) }

// verify
println map['c']

그것은 기본적으로 내 질문에서와 동일합니다 ... 방금 .putAt 대신 map [it.k] = it.v를 가졌습니다. 나는 한 줄의 라이너를 찾고있었습니다.
danb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.