首页 > 解决方案 > 根据列的值使用 Groovy 重新组合列表

问题描述

我有一个包含街道地址、邮政编码、国家、省份等的列表......

我想连续重新组合同一条街道的所有门牌号码,例如:

City         Street              Cp        Housenumber   etc......
Qc      Rue Prudent-Cloutier   G0E 1V0        1-3,6,9-11
Qc      Rue Godin              G0E 1V0        102-104
.
.
.
.

所以我所做的是获取街道列的所有唯一值并将它们添加到一个新列表中,并将其与第一个列表与所有值进行比较,但我总是得到空值......

def str ='''\

 

<Table>
    <Columns Items="6">
        <Column Name="Id" Type="String"/>
        <Column Name="Text" Type="String"/>
        <Column Name="Highlight" Type="String"/>
        <Column Name="Cursor" Type="Integer"/>
        <Column Name="Description" Type="String"/>
        <Column Name="Next" Type="String"/>
    </Columns>
    <Rows Items="8">
        <Row Id="CA|CP|A|800140112" Text="1 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15635710" Text="3 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|21493732" Text="6 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|16097589" Text="9 Rte Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|17847787" Text="11 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15997187" Text="102 Rue Municipale" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15997137" Text="102 Rue Godin" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15997149" Text="104 Rue Godin" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>   
    </Rows>

</Table>

 

'''
def xml = new XmlParser().parseText(str)
List newAddressList=new ArrayList();
List StreetsAdress=new ArrayList();
List newUniqueList=new ArrayList();
def iter_String = xml.Rows[0].@Items
int iter = new Integer(iter_String).intValue()
z=0
for (int i=0; i < iter ; i++){
    LastId = xml.Rows[0].Row[i].@Id
    def (Country, Type) = LastId.tokenize( '\\|' )
    Text = xml.Rows[0].Row[i].@Text
    def (HouseNumber, Street) = Text.split(" " ,2)
    if (HouseNumber!="CP"){
    Description = xml.Rows[0].Row[i].@Description
    def (City,City_ab,Code_postale ) = Description.tokenize( ',' )
    newAddressList.add(['RecordId1':z++,'Country1 ':Country,'HouseNumber1':HouseNumber,'Street1': Street,'City1':City,'City_ab1':City_ab,'Code_postale1':Code_postale]);
    StreetsAdress.add(['StreetList':Street]);
    newUniqueList = StreetsAdress.unique();
    }
}
println newUniqueList

所以我想知道如何比较 newUniqueList(仅包含没有重复的街道)和 newAddressList(包含所有信息)并重新组合所有 houseNumbers 。谢谢你的帮助 !

标签: listgroovygroup-by

解决方案


以下代码:

import groovy.xml.*

def data = '''
<Table>
    <Columns Items="6">
        <Column Name="Id" Type="String"/>
        <Column Name="Text" Type="String"/>
        <Column Name="Highlight" Type="String"/>
        <Column Name="Cursor" Type="Integer"/>
        <Column Name="Description" Type="String"/>
        <Column Name="Next" Type="String"/>
    </Columns>
    <Rows Items="8">
        <Row Id="CA|CP|A|800140112" Text="1 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15635710" Text="3 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|21493732" Text="6 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|16097589" Text="9 Rte Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|17847787" Text="11 Rue Prudent-Cloutier" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15997187" Text="102 Rue Municipale" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15997137" Text="102 Rue Godin" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>
        <Row Id="CA|CP|A|15997149" Text="104 Rue Godin" Highlight="" Cursor="0" Description="Mont-Saint-Pierre, QC, G0E 1V0" Next="Retrieve"/>   
    </Rows>
</Table>
'''

def xml = new XmlSlurper().parseText(data) 

def collapsed = xml.Rows.Row.groupBy { row -> 
  def matcher = row.@Text =~ /[^0-9]+/
  matcher[0]
}.collect { street, rows -> 
  def nums = rows.collect { row -> 
    row.@Text.text().tokenize(' ').first() as Integer
  }.sort()

  def tokens = rows.first().@Description.text().tokenize(',')
  def range = nums.size() == 1 ? "${nums.first()}" : "${nums.first()}-${nums.last()}"
  [City: tokens[1].trim(), Street: street.trim(), Cp: tokens[2].trim(), HouseNumber: range]
}


def headers = ['City', 'Street', 'Cp', 'HouseNumber']
def widths = headers.collectEntries { header -> 
  [header, collapsed.collect { it[header].length() }.max() + 4]
}

headers.each { header ->
  print(header.padRight(widths[header]))
}
println()

collapsed.each { row -> 
  headers.each { header -> 
    print(row[header].padRight(widths[header]))
  }
  println()
}

运行时,打印:

─➤ groovy solution.groovy
City  Street                      Cp         HouseNumber
QC    Rue Prudent-Cloutier        G0E 1V0    1-11
QC    Rte Rue Prudent-Cloutier    G0E 1V0    9
QC    Rue Municipale              G0E 1V0    102
QC    Rue Godin                   G0E 1V0    102-104

...加倍努力,对输出进行了一些格式化,这使解决方案复杂化,但这应该为您提供一个如何使用它的示例。

由于这有点复杂,我将对代码的主要部分添加一些解释。

解释:

xml.Rows.Row.groupBy { row -> 
  def matcher = row.@Text =~ /[^0-9]+/
  matcher[0]
}

这将获取由返回的行列表xml.Rows.Row并将它们分组到 Row.Text 的非数字部分(即没有数字的街道名称,例如:“Rue Prudent-Cloutier”)。groupBy返回 a Map<street name, List<Row>,换句话说,按地址所在的街道分组的行(不包括数字)。

.collect { street, rows -> 
  ...
}

这将遍历Map<street name, List<Row>>并创建一个列表。换句话说,对于每条街道,这个闭包( 内部的部分{ })将使用街道名称(“Rue Prudent-Cloutier”)和rows列表中具有该街道名称的所有行调用一次。将collect返回一个List<something>wheresomething是这个闭包返回的任何内容。

  def nums = rows.collect { row -> 
    row.@Text.text().tokenize(' ').first() as Integer
  }.sort()

获取特定街道(例如“Rue Prudent-Cloutier”)的所有行,提取街道编号(1、3 等),将它们转换为整数并进行排序,以便numsaList<Integer>具有最小的数字,最大的最后。

  def tokens = rows.first().@Description.text().tokenize(',')

拆分描述文本,例如Mont-Saint-Pierre, QC, G0E 1V0返回 a 的逗号List<String>(在本例中为 `['Mont-Saint-Pierre', 'QC', 'G0E 1V0'])。

  def range = nums.size() == 1 ? "${nums.first()}" : "${nums.first()}-${nums.last()}"

获取已排序的门牌号码并创建单个数字字符串9或范围字符串1-11并将其存储在变量中range

[City: tokens[1].trim(), Street: street.trim(), Cp: tokens[2].trim(), HouseNumber: range]

这最终从.collect { street, rows -> ... }. 这是 groovy map 语法,换句话说,collect 中的每次迭代都将返回一个 map,collapsed因此将具有 type List<Map<String, String>>,或者更简单的示例,collapsed将具有以下结构:

[[City: QC, Street: Rue Prudent-Cloutier, Cp: G0E 1V0, HouseNumber:1-11],
 [City: QC, Street: Rue Municipale, Cp: G0E 1V0, HouseNumber:102]
 ...
]

至于你应该把你的条件放在哪里,我认为你必须修改以适应你的需要。


推荐阅读