Сведения о вопросе

Математик

22:24, 16th August, 2020

Теги

ярлык для создания карты из списка в groovy?

Просмотров: 506   Ответов: 8

Я бы хотел немного сортанд для этого:

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

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



  Сведения об ответе

прога

14:46, 12th August, 2020

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

Оператор + также может использоваться вместо << .


  Сведения об ответе

FAriza

14:11, 26th August, 2020

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

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

И, пока вы этим занимаетесь, вы, вероятно, хотите определить методы как категории, а не прямо на metaClass. Таким образом, вы можете определить его один раз для всех коллекций:

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


  Сведения об ответе

piter

21:06, 1st October, 2020

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


  Сведения об ответе

LAST

10:30, 11th August, 2020

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

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


  Сведения об ответе

repe

15:06, 15th August, 2020

ладно... Я играл с этим немного больше, и я думаю, что это довольно крутой метод...

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

теперь любой подкласс карты или коллекции имеет этот метод...

здесь я использую его для реверса ключа / значения в карте

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

и здесь я использую его для создания карты из списка

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

теперь я просто помещаю это в класс, который вызывается при запуске моего приложения, и этот метод доступен во всем моем коде.

EDIT:

чтобы добавить метод ко всем массивам...

Object[].metaClass.collectMap = collectMap


  Сведения об ответе

LIZA

03:57, 7th August, 2020

Если вам нужна простая пара ключ-значение, то достаточно использовать метод 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]]


  Сведения об ответе

fo_I_K

15:27, 29th August, 2020

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

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

это добавляет метод collectMap ко всем ArrayLists... Я не знаю, почему добавление его в список или коллекцию не сработало.. Думаю, это уже другой вопрос... но теперь я могу это сделать...

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

от списка до расчетной карты с одним закрытием... именно то, что я искал.

Edit: причина, по которой я не смог добавить метод в список интерфейсов и коллекцию, заключалась в том, что я этого не делал:

List.metaClass.enableGlobally()

после этого вызова метода можно добавить методы в интерфейсы.. что в данном случае означает, что мой метод collectMap будет работать на диапазонах, подобных этому:

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

что дает карту: [0:0, 1:2, 2:4]


  Сведения об ответе

pumpa

03:53, 4th August, 2020

А как насчет чего-то вроде этого?

// 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']


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться