使用循环将地图元素添加到列表

3
我试图用从查询/findAllBy中创建的对象来填充一个地图列表...但最终我总是得到与循环中最后一个地图相同的地图列表。
我已经设定了断点并逐步执行该方法,发现1)从查询返回的数据是正确的,2)当我逐步执行循环时,数据被正确地插入到地图中,3)失败是在将地图插入列表中。我使用的所有将元素插入列表的方法(.add、.push、<<、list[(i)] = map等)都会覆盖列表中之前的所有元素。
请帮忙解决。我不知道为什么会出现这种情况。希望这对你们中的某个人来说是个容易的问题。
def shiftRecords = Shift.findAllByUserAndStartTimeBetween( userInstance, startDate, endDate )
ArrayList allShifts = new ArrayList()
LinkedHashMap thisShift = new LinkedHashMap()
def size = shiftRecords.size()

for ( int i = 0; i < size; i++ ){
    thisShift["id"] = shiftRecords[(i)].id
    thisShift["user"] = shiftRecords[(i)].user
    thisShift["startTime"] = shiftRecords[(i)].startTime
    thisShift["posCode"] = shiftRecords[(i)].posCode
    thisShift["deptCode"] = shiftRecords[(i)].deptCode
    thisShift["billingIDX"] = shiftRecords[(i)].billingIDX

    Position thisPos = Position.findByPositionCode( thisShift.posCode )
    thisShift["posTitle"] = thisPos.shortTitle
    thisShift["deptTitle"] = thisPos.departmentTitle

    allShifts.add( (i), thisShift )
}

我希望将所有Shift的结果作为地图列表,并从Shift查询结果中选择数据。 我尝试使用shiftRecords.each和eachWithIndex。 问题出现在任何类型的循环中,当thisShift地图插入到allShifts中时。 它不仅插入了一个地图实例,而且用当前的thisShift地图替换了所有列表元素。

2个回答

3
def shiftRecords = Shift.findAllByUserAndStartTimeBetween( 
                               userInstance, startDate, endDate )
ArrayList allShifts = new ArrayList()
def size = shiftRecords.size()

for ( int i = 0; i < size; i++ ){
    LinkedHashMap thisShift = new LinkedHashMap()
    thisShift["id"] = shiftRecords[(i)].id
    thisShift["user"] = shiftRecords[(i)].user
    thisShift["startTime"] = shiftRecords[(i)].startTime
    thisShift["posCode"] = shiftRecords[(i)].posCode
    thisShift["deptCode"] = shiftRecords[(i)].deptCode
    thisShift["billingIDX"] = shiftRecords[(i)].billingIDX

    Position thisPos = Position.findByPositionCode( thisShift.posCode )
    thisShift["posTitle"] = thisPos.shortTitle
    thisShift["deptTitle"] = thisPos.departmentTitle

    allShifts << thisShift
}

每次迭代shiftRecords时,您需要创建一个新地图。虽然以上代码可以在 Groovy 中过度简化,如下所示:
def shiftRecords = Shift.findAllByUserAndStartTimeBetween( 
                               userInstance, startDate, endDate )
def allShifts = []

shiftRecords.each{
    def thisShift = [:]
    thisShift.id = it.id
    thisShift.user = it.user
    thisShift.startTime = it.startTime
    thisShift.posCode = it.posCode
    thisShift.deptCode = it.deptCode
    thisShift.billingIDX = it.billingIDX

    Position thisPos = Position.findByPositionCode( thisShift.posCode )
    thisShift.posTitle = thisPos.shortTitle
    thisShift.deptTitle = thisPos.departmentTitle

    allShifts << thisShift
}

“ahem” 可能仍然更加时髦(尽管我们必须注意不要过于时髦) - tim_yates
@tim_yates说得很对,我喜欢采取渐进式的方法并指出方法上的错误。原帖作者:“我们能否进一步简化你的解决方案?”我:“当然可以,看看其他答案吧 ;)” - dmahapatro
谢谢你的回答。这么简单,我为了它纠结了很久,感到有些尴尬。我是Groovy和Grails的新手,有时会把事情复杂化。 - CheddarMonkey
@CheddarMonkey,正如你所说,你是Groovy和Grails的新手。你需要知道接受的答案是如何工作的,而不仅仅是使用它。探索一下collect的工作原理。我本可以花更多时间给你相同的答案(或类似的答案),而不是指出你的错误。但我更喜欢后者。 :) - dmahapatro
@CheddarMonkey 从未要求接受我的答案。在你的情况下,Tim的答案将是最佳方法。 :) - dmahapatro
我修改了它,因为你的答案更有帮助。 - CheddarMonkey

3

尝试:

def shiftRecords = Shift.findAllByUserAndStartTimeBetween( userInstance, startDate, endDate )
def allShifts = shiftRecords.collect { it ->
    def pos = Position.findByPositionCode( it.posCode )
    [ id         : it.id,
      user       : it.user,
      startTime  : it.startTime,
      posCode    : it.posCode,
      deptCode   : it.deptCode,
      billingIDX : it.billingIDX,
      posTitle   : pos.shortTitle,
      deptTitle  : pos.departmentTitle ]
}

笑,我也把我的解决方案简单化了。 :) - dmahapatro
感谢您为答案增添更多的GROOVE。我需要尽可能多的建议。您和@dmahapatro提供了出色的答案。 - CheddarMonkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接