Вопрос

Мне бы хотелось немного разобраться в этом:

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] }
}

но я ничего не видел в документах...я что-то упускаю?или я просто слишком ленив?

Это было полезно?

Решение

Недавно я столкнулся с необходимостью сделать именно это:преобразование списка в карту.Этот вопрос был опубликован до выхода 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]}
}

Тот Самый + оператор также может быть использован вместо <<.

Другие советы

Проверьте "впрыснуть".Настоящие любители функционального программирования называют это "сворачиванием".

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')
}

Был тем самым Группировка метод был недоступен, когда был задан этот вопрос?

Кроме того, если вы используете коллекции Google (http://code.google.com/p/google-collections/), вы можете сделать что-то вроде этого:

  map = Maps.uniqueIndex(list, Functions.identity());

ОК...Я еще немного поиграл с этим и думаю, что это довольно классный метод...

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

Если вам нужна простая пара ключ-значение, то метод collectEntries должно хватить.Например

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

Но если вам нужна структура, похожая на Multimap, в которой для каждого ключа имеется несколько значений, то вам следует использовать groupBy способ

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

Я не могу найти ничего встроенного...но используя ExpandoMetaClass, я могу сделать это:

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

это добавляет метод collectMap ко всем спискам массивов...Я не уверен, почему добавление его в Список или Коллекцию не сработало..Я думаю, это к другому вопросу...но теперь я могу это сделать...

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]

Как насчет чего-нибудь подобного?

// 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']
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top