Groovy方法合并两个映射列表与一些计算

时间:2017-02-13 18:21:12

标签: groovy

我需要合并到地图,同时执行一些计算,例如,下面的地图总是大小相同

CREATE TYPE UDT1 (
   field1 text,
   field2 int,
   field3 text
);

CREATE TYPE UDT2 (
   field1 boolean,
   field2 float
);

CREATE TABLE cypher.table1 (
   id int PRIMARY KEY,
   list1 list<frozen<UDT1>>,
   data text,
   set1 set<frozen<UDT2>>
) WITH bloom_filter_fp_chance = 0.01
    AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
    AND comment = ''
    AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
    AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND crc_check_chance = 1.0
    AND dclocal_read_repair_chance = 0.1
    AND default_time_to_live = 0
    AND gc_grace_seconds = 864000
    AND max_index_interval = 2048
    AND memtable_flush_period_in_ms = 0
    AND min_index_interval = 128
    AND read_repair_chance = 0.0
    AND speculative_retry = '99PERCENTILE';

我想要这张地图

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

请你分享一个常规方法来完成这项任务。感谢

3 个答案:

答案 0 :(得分:3)

我能提出的最流行的代码:

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

编辑:如Tim所述,只要两个输入列表(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]

我已将map1map2重命名为list1list2,因为它们实际上是两个包含内部地图的列表。

代码有点简洁,如果您不习惯transpose以及常规的传播和地图操作,可能需要一些解释。

解释

  1. [list1, list2] - 首先我们创建一个新列表,其中两个现有列表是元素。所以我们现在有一个列表列表,其中内部列表中的元素是映射。
  2. .transpose() - 然后我们调用transpose,当您第一次看到它时可能需要一些努力。如果您有一个列表列表,您可以看到转置为将列表翻转到另一个方向&#34;。
  3. 在我们的案例中有两个列表:

    [[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 + map中返回一个合并的地图。因此,使用groovy spread operator *.,我们会在每个地图列表上调用sum()
    2. 即:

      [[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属性添加到地图中,以便我们遍历现在的两个地图列表,并添加余额作为配额计算 - copiesToDate。 each构造返回它正在处理的列表,这是我们分配给x的内容。

答案 1 :(得分:2)

另一个有趣的选择: - )

def result = (map1 + map2).groupBy { it.name }
                          .values()
                         *.sum()
                          .collect { it << ['balance': it.quota - it.copiesToDate] }
  • 将列表添加到一起
  • 分组名称
  • 获取分组值并将它们连接起来
  • 然后为每个人制定balance

答案 2 :(得分: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]
}