2017-02-13 7 views
3

мне нужно объединить с карты в то время как выполнить некоторые вычисления, например, имеющие следующие карты, которые всегда будут иметь тот же размерGroovy способ объединить два списка карт с некоторыми расчетами

def map1 = [ 
    [name: 'Coord1', quota: 200], 
    [name: 'Coord2', quota: 300] 
] 

def map2 = [ 
    [name: 'Coord1', copiesToDate: 270], 
    [name: 'Coord2', copiesToDate: 30] 
] 

Я хочу, чтобы получить эту карту

def map3 = [ 
    [name: 'Coord1', quota: 200, copiesToDate: 60, balance: 140], 
    [name: 'Coord2', quota: 300, copiesToDate: 30, balance: 270] 
] 

Прямо сейчас я пытаюсь с этим решением и его работой

def map4 = map1.collect { m1 -> 
[ 
    name: m1.name, 
    quota: m1.quota, 
    copiesToDate: map2.find { m2 -> 
     m1.name == m2.name 
    }.copiesToDate, 
    balanceToDate: m1.quota - map2.find { m2 -> 
     m1.name == m2.name 
    }.copiesToDate 
]} 

Могу года u, пожалуйста, поделитесь великолепным способом выполнения этой задачи. Благодаря

ответ

2

оптимистичную код, который я мог придумать:

def map3 = [map1, map2].transpose()*.sum().each { m -> 
    m.balance = m.quota - m.copiesToDate 
} 

редактирования: как отмечает Тим, этот код работает до тех пор, как два входных списков (map1 и map2) одного и того же размера и иметь карты в порядке. Если это не так, я бы порекомендовал ответ Тима, который обрабатывает эти случаи.

Приведенное выше возвращает карту, определенную в вашем вопросе. Следующий код:

def list1 = [ 
    [name: 'Coord1', quota: 200], 
    [name: 'Coord2', quota: 300] 
] 

def list2 = [ 
    [name: 'Coord1', copiesToDate: 60], 
    [name: 'Coord2', copiesToDate: 30] 
] 

def x = [list1, list2].transpose()*.sum().each { m -> 
    m.balance = m.quota - m.copiesToDate 
} 

x.each { 
    println it 
} 

демонстрирует идею и печатает:

[name:Coord1, quota:200, copiesToDate:60, balance:140] 
[name:Coord2, quota:300, copiesToDate:30, balance:270] 

Я переименованный map1 и map2 в list1 и list2, так как они на самом деле два списка, содержащих внутренние карты.

Код несколько кратким и может потребоваться немного пояснения, если вы не используете transpose и операции с разворотом и картографией.

Объяснение:

  1. [list1, list2] - сначала создать новый список, в котором две существующие списки элементов. Итак, теперь у нас есть список списков, в которых элементы во внутренних списках являются картами.
  2. .transpose() - тогда мы вызываем transpose, которому может потребоваться немного усилий, чтобы понять, когда вы видите его в первый раз. Если у вас есть список списков, вы можете увидеть транспонирование, перелистывая списки «в другое направление».

В нашем случае два списка:

[[name:Coord1, quota:200], [name:Coord2, quota:300]] 
[[name:Coord1, copiesToDate:60], [name:Coord2, copiesToDate:30]] 

стал:

[[name:Coord1, quota:200], [name:Coord1, copiesToDate:60]] 
[[name:Coord2, quota:300], [name:Coord2, copiesToDate:30]] 

т.е. после того, как транспонирования, все, что касается Coord1 в первом списке, и все, что касается Coord2 находится в второй.

  1. Каждый из списков, которые мы имеем сейчас, представляет собой список карт. Но мы хотим только одну карту для Coord1 и одну карту для Coord2. Поэтому для каждого из приведенных выше списков нам нужно объединить или объединить содержащиеся карты в одну карту. Мы делаем это, используя тот факт, что в карте groovy + map возвращается объединенная карта.Используя , мы поэтому вызываем sum() в каждый список карт.

т.е .:

[[name:Coord1, quota:200], [name:Coord1, copiesToDate:60]].sum() 

вычисляет в:

[name:Coord1, quota:200, copiesToDate:60] 

и:

[[name:Coord2, quota:300], [name:Coord2, copiesToDate:30]].sum() 

в:

[name:Coord2, quota:300, copiesToDate:30] 
  1. Наконец, мы хотим добавить к картам свойство balance, чтобы мы перебирали то, что теперь представляет собой список двух карт, и добавляем баланс в качестве вычисления квоты - copyToDate. Конструкция each возвращает список, в котором он работает, и который мы назначаем x.
+0

Transpose опирается на списки, имеющие одинаковый порядок, без недостающих элементов в каждом из них –

+0

True. Поэтому для списков разной длины или порядка вам придется делать что-то еще. Оператор явно указал, что карты имеют одинаковый размер, который я выбрал для чтения, поскольку списки имеют одинаковый размер:). Для смены порядка вы наиболее корректны, транспонирование не будет работать. –

1

Не звоните find дважды. Используйте метод Map.plus() для добавления новых записей. Удалите имена из map2.

def map3 = map1.collect {m1 -> 
    def m2 = map2.find {it.name == m1.name} ?: [copiesToDate: 0] 
    m1 + m2 + [balance: m1.quota - m2.copiesToDate] 
} 
2

Другим вариант для удовольствия :-)

def result = (map1 + map2).groupBy { it.name } 
          .values() 
         *.sum() 
          .collect { it << ['balance': it.quota - it.copiesToDate] } 
  • добавить списки вместе
  • группы под названием
  • получить сгруппированное значение и сцепить их
  • то для каждого из них, выработать balance