首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Groovy根据列的值对列表进行重新分组

使用Groovy根据列的值对列表进行重新分组
EN

Stack Overflow用户
提问于 2021-02-24 05:16:53
回答 1查看 62关注 0票数 0

我有一个带有街道地址,邮政编码,国家,省份等的列表。

我想将同一条街道的所有门牌号重新分组,如下所示:

代码语言:javascript
复制
City         Street              Cp        Housenumber   etc......
Qc      Rue Prudent-Cloutier   G0E 1V0        1-3,6,9-11
Qc      Rue Godin              G0E 1V0        102-104
.
.
.
.

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

代码语言:javascript
复制
def str ='''\

 


        
        
        
        
        
        
    
        
        
        
        
        
        
        
           
    
    
    



 

'''
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进行重组。感谢您的帮助!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-25 02:30:48

以下代码:

代码语言:javascript
复制
import groovy.xml.*

def data = '''

        
        
        
        
        
        
    
        
        
        
        
        
        
        
           
    
    
    

'''

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

运行时,打印:

代码语言:javascript
复制
─➤ 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

...went额外的一步,并对输出进行了一些格式化,这会使解决方案变得复杂,但这应该会为您提供一个如何使用它的示例。

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

解释:

代码语言:javascript
复制
xml.Rows.Row.groupBy { row -> 
  def matcher = row.@Text =~ /[^0-9]+/
  matcher[0]
}

返回的行列表。xml.Rows.Row并将它们分组到Row.Text的非数字部分(即不带数字的街道名称,例如:"Rue Prudent-Cloutier")。groupBy返回一个Map换句话说,这些行是按地址所在的街道分组的(不包括数字)。

代码语言:javascript
复制
.collect { street, rows -> 
  ...
}

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

代码语言:javascript
复制
def nums = rows.collect { row -> 
    row.@Text.text().tokenize(' ').first() as Integer
  }.sort()

获取特定街道的所有行,例如"Rue Prudent-Cloutier",提取街道编号(1、3等),将它们转换为整数并进行排序,然后nums是一个List最先是最小的数字,最后是最大的数字。

代码语言:javascript
复制
def tokens = rows.first().@Description.text().tokenize(',')

拆分说明文本,如下所示Mont-Saint-Pierre, QC, G0E 1V0在逗号返回时List(在本例中为`‘圣皮尔山’,'QC','G0E 1V0‘)。

代码语言:javascript
复制
def range = nums.size() == 1 ? "${nums.first()}" : "${nums.first()}-${nums.last()}"

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

代码语言:javascript
复制
[City: tokens[1].trim(), Street: street.trim(), Cp: tokens[2].trim(), HouseNumber: range]

这最终创建了来自.collect { street, rows -> ... }。这是groovy的map语法,换句话说,collect中的每个迭代都将返回一个map和collapsed将因此具有类型List>,或者用一个更简单的例子,collapsed会有这样的结构:

代码语言:javascript
复制
[[City: QC, Street: Rue Prudent-Cloutier, Cp: G0E 1V0, HouseNumber:1-11],
 [City: QC, Street: Rue Municipale, Cp: G0E 1V0, HouseNumber:102]
 ...
]

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66341218

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档