2014-10-14 4 views
1

Мне нужно изменить элементы карты при повторении карты, в моем случае вычесть некоторые элементы (список). Как это:Groovy изменять элементы карты при повторении карты

def a = [ 
    1: [1, 2, 3], 
    2: [3, 2, 4], 
    3: [3, 2, 4], 
    4: [5, 2, 1], 
] 
def b = [3] 
println a 
a.values().each{ tr -> 
    tr = tr - b 
} 
println a 

a карта не изменилась. Результат:

[1:[1, 2, 3], 2:[3, 2, 4], 3:[5, 3, 1], 4:[5, 2, 1]] 
[1:[1, 2, 3], 2:[3, 2, 4], 3:[5, 3, 1], 4:[5, 2, 1]] 

Однако, я хочу, чтобы результат [1:[1, 2], 2:[2, 4], 3:[5, 1], 4:[5, 2, 1]]. Что я делаю неправильно? Из-за того, что исходная карта довольно большая, я не хочу строить другую карту с меньшим количеством элементов (карта результатов).

+0

, что «большой»? несколько сотен? несколько тысяч? Миллионы? – robkuz

ответ

5

работа непосредственно на карте вместо:

a.keySet().each{ 
    a[it]-=b 
} 

В своем коде вы присваиваете результат в локальной переменной.

Если у вас есть сомнения по поводу количества изменений, которые вы можете использовать в removeAll() или итерации свыше b и remove() каждый. Они меняют список на месте.

+0

Для тех, кто ищет: «Groovy: изменять элементы при повторении карты» (показано первым в google), он работает с: 'a.each {it.val = }', как показано в принятом ответе: http://stackoverflow.com/questions/20481006/update-map-using-findall-and-each-in-groovy или используя 'a.collect {it.getNewValue()}', как описано здесь: http: //mrhaki.blogspot .jp/2010/01/заводной-благость применить метод-к-all.html – lepe

1

Или вы могли бы использовать collectEntries:

def a = [ 
    1: [1, 2, 3], 
    2: [3, 2, 4], 
    3: [3, 2, 4], 
    4: [5, 2, 1], 
] 
def b = [3] 

a = a.collectEntries { k, v -> [k, v - b] } 
1

Во-первых, я рекомендую использовать равнину, ваниль Java List.remove(Object) вместо Groovy, List.minus(List). Это, является изменение строки:

def b = [3] 

и

tr = tr - b 

в следующем:

def b = 3 

и

tr.remove((Object)b) 

Проблемы с прежней парой заявлений заключается в том, что выражение n tr - b создает новый объект списка. Этот список присваивается локальной переменной tr. Между тем первоначальный список, тот, который находится на Карте, исходное значение tr перед назначением, остается неизменным.

Явный метод List.remove(Object), хотя и не как «Groovy» как вычитание, работает в исходном списке без создания нового списка. Помимо создания правильного результата, этот метод также имеет то преимущество, что он не создает новый список для каждой записи карты.

Примечание, что необходимо наложить b на Object в явном виде. Groovy выполняет динамическую отправку для разрешения перегрузки оператора. Без приведения в действие, хотя статический тип b уже равен Object, Groovy обнаружил бы, что b является целым числом и вызывает List.remove(int) вместо List.remove(Object), что не получится. С актерским составом, Groovy имеет достаточно намека, чтобы делать правильные вещи.


Во-вторых, я рекомендую использовать Map.each вместо Map.values() прикован к List.each.Таким образом, заменив строку:

a.values().each { tr -> 

следующим:

a.each { key, tr -> 

Первое утверждение вызывает карту для создания экземпляра список, содержащий все значения, в то время как последнее утверждение не делает. Хотя фактические «значения» в первом случае совпадают с значениями из карты, вы сказали, что карта была настолько большой, что вы не хотели создавать целую новую карту. Поэтому я также предполагаю, что вы не хотите создавать целый список из объектов ценности карты.


Если вы будете следовать этим рекомендациям, ваш окончательный код должен выглядеть следующим образом:

def a = [ 
    1: [1, 2, 3], 
    2: [3, 2, 4], 
    3: [3, 2, 4], 
    4: [5, 2, 1], 
] 
def b = 3 
println a 
a.each{ k, v -> 
    v.remove((Object)b) 
} 
println a 
Смежные вопросы