Groovy, список сортировки вызывает исключение одновременной модификации - PullRequest
2 голосов
/ 02 марта 2012

Все еще изучая веревки с Groovy, эта проблема запутала меня с прошлой ночи.Не уверен, почему он вызывает исключение concurrentmod ... (Java 1.6, Groovy 1.8.4)

У меня есть список ключей ... [1,2,3,4,5,6,7,8,9,10,11,12,13]

Я собираю список, используя пользовательскийfunction partitionList(keys,3) Я получил от здесь (не могу использовать java.List.Collate, не на 1.8.6)

Теперь у меня есть список списков ... [[0,1,2],[3,4,5],[6,7,8],[9,10,11],[12,13]]

Если число созданных подсписков нечетное, я удаляю последний подсписок [12,13] и перераспределяю его ключи среди других подсписков, начиная по порядку, создавая ...

[[0,1,2,12],[3,4,5,13],[6,7,8],[9,10,11]]

Исключение возникает при итерации значений последнего подсписка.Не знаю, почему, поскольку я повторяю список и изменяю совершенно другой список в этом цикле ...

ОБНОВЛЕНИЕ:

Интересно ... если я наденуне использовать функцию paritionList(), заменяя def keyRanges = partitionList( keys, 3) явным списком списков ... def keyRanges = [[0,1,2],[3,4,5],[6,7,8],[9,10,11],[12,13]] проблема исчезает.Поэтому я считаю, что функция partitionList () делает что-то, что вызывает исключение

class CollateListTest {

    static main(args) {    
        def keys = (0..13).toList()

        //partition the keys into a list of lists 
        def keyRanges = partitionList( keys, 3)
        println 'Key range sets...'
        for( keyRange in keyRanges)
            println keyRange

        //if odd number of partitions, 
        //remove last sub list and redistribute values over other lists
        if( (keyRanges.size() % 2) != 0){
            def lastKeyRange = keyRanges.remove( keyRanges.size() - 1 )
            println 'removed range: ' + lastKeyRange

                    // ** EXCEPTION HERE **         
            lastKeyRange.eachWithIndex{ k, index ->
                println 'adding: ' + k
                keyRanges[ index % keyRanges.size()].add( k)
            }
        }
    }

    //from stackoverflow.com/questions/2924395/
    static def partitionList(list, size) {
        def partitions = []
        int partitionCount = list.size() / size

        partitionCount.times { partitionNumber ->
            def start = partitionNumber * size
            def end = start + size - 1
            partitions << list[start..end]
        }

        if (list.size() % size) partitions << list[partitionCount * size..-1]
        return partitions
    }
}

1 Ответ

2 голосов
/ 02 марта 2012

Используемый метод partitionList разделяет список с помощью List.getAt (Range) .Это возвращает представление в исходный список, но не копирует данные, поэтому любые изменения в подсписке также влияют на исходный.один из подсписков косвенно влияет на подсписок, который вы перебираете.Вместо того, чтобы изменять подсписок, просто создайте новый.Например:

if( (keyRanges.size() % 2) != 0){
    def lastKeyRange = keyRanges.remove( keyRanges.size() - 1 )
    println 'removed range: ' + lastKeyRange

    lastKeyRange.eachWithIndex{ k, index ->
        println 'adding: ' + k
        def newRange = []
        newRange.addAll(keyRanges[ index % keyRanges.size()])
        newRange.add(k)
        keyRanges[ index % keyRanges.size()] = newRange

    }
}
...