0

I have created a new LinkedHashMap 'workingStrData' using 'strData' and I still get the error.

I am trying to remove some items from this LinkedHashMap based of another list.

The way strData is structured is

    strData = [components[{key1:value1}{key2:value2}...]]     

    def workingStrData = new LinkedHashMap(strData)
    List componentsToRemove = ['item1','item2'...]
    int itemsRemoved = 0

    workingStrData.components.eachWithIndex {
            comp, workingStrIndex ->
                println("Index: "+workingStrIndex+" Component: "+comp.number)

                def baditem = comp.number in componentsToRemove
                if (baditem) {
                    strData.components.remove(workingStrIndex - itemsRemoved)
                    itemsRemoved += 1
                }
        }

4 Answers4

1

You cannot remove an element from a list while iterating with each or with eachWithIndex which by the way is a bad practice. Groovy offers much more elegant and simpler solutions.

As suggested, try retainAll() or as suggested here, try removeAll():

def strData = [
    components : [
        [number: 'item0'],
        [number: 'item1']
    ]
]

def componentsToRemove = [
    'item1','item2'
]

componentsToRemove.each { removeIt ->
    strData.components.removeAll { it.number == removeIt }
}

assert strData.components == [[number: 'item0']]
Catalin
  • 366
  • 2
  • 8
0

It is not complaining about the strData/workingStrData maps, it is complaining about the List referenced by the value of the "components" key in the map.

You know, the List you are actually iterating, and the List you actually call remove(int index) on.

You don't actually iterate or modify the map, so copying that is meaningless.

Andreas
  • 154,647
  • 11
  • 152
  • 247
0

Eddiel is right, you can't modify array ( and strData.components is an array ) while you iterate it.

Even if you created a copy of root map def workingStrData = new LinkedHashMap(strData) the content of this map referencing the same data.

it means that workingStrData.components and strData.components referencing the same array.


groovy styled code to modify array:

def strData = [
    components:[
        [number:'111', name:'aaa'],
        [number:'222', name:'bbb'],
        [number:'333', name:'ccc'],
        [number:'444', name:'ddd'],
    ]
]
List componentsToRemove = ['222','333']

//--------------------------------------
// if you want to keep original data:
def modData = [
    components: strData.components.findAll{c-> c.number in componentsToRemove }
]

println "original           : $strData"
println "modified           : $modData"

//--------------------------------------
// if you want to modify existing data
strData.components.retainAll{c-> !( c.number in componentsToRemove) }
println "original (modified): $strData"
daggett
  • 26,404
  • 3
  • 40
  • 56
-1

You can not modify the map unless you use an iterator or you use a synchronized collection. This is by design in Java. Check https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedMap-java.util.Map- to wrap your collection or, remove the elements using the iterator's own remove function.

In java, that would look like this:

Iterator<String> iterator = workingStrData.keySet().iterator();
while (iterator.hasNext()) {
    iterator.next();
    iterator.remove();
}

// workingStrData is empty at this point.
Eddie Lopez
  • 1,101
  • 7
  • 15
  • The code isn't modifying the `strData` map, it is modifying a nested list, stored as the value of the key `"components"` in the `strData` map. – Andreas Feb 01 '21 at 17:10