В Kotlin, как изменить содержимое списка во время итерации
у меня есть список:
val someList = listOf(1, 20, 10, 55, 30, 22, 11, 0, 99)
и я хочу повторить его при изменении некоторых значений.  Я знаю, что могу сделать это с map но это делает копию списка.  
val copyOfList = someList.map { if (it <= 20) it + 20 else it }
как это сделать без копии?
Примечание: этот вопрос намеренно написан и на него отвечает автор (Вопросы С Ответами), так что идиоматические ответы на часто задаваемые темы Котлина присутствуют в SO. Также уточните некоторые действительно старые ответы, написанные для Альф Котлина, которые не точны для современного Котлина.
1 ответов
во-первых, не все копирование списка плохо. Иногда копия может воспользоваться кэшем CPU и быть чрезвычайно быстрой, это зависит от списка, размера и других факторов.
во-вторых, для изменения списка "на месте" вам нужно использовать тип списка, который является изменяемым.  В вашем примере вы используете listOf возвращает List<T> интерфейс, и это только для чтения.  Вам нужно напрямую ссылаться на класс изменяемого списка (т. е. ArrayList), или это идиоматический Котлин, чтобы использовать помощника функции arrayListOf или linkedListOf создать MutableList<T> ссылка.  После этого вы можете повторить список, используя listIterator() который имеет метод мутации set().
// create a mutable list
val someList = arrayListOf(1, 20, 10, 55, 30, 22, 11, 0, 99)
// iterate it using a mutable iterator and modify values 
val iterate = someList.listIterator()
while (iterate.hasNext()) {
    val oldValue = iterate.next()
    if (oldValue <= 20) iterate.set(oldValue + 20)
}
это изменит значения в списке по мере итерации и эффективно для всех типов списков. Чтобы сделать это проще, создайте полезные функции расширения, которые можно использовать повторно (см. ниже).
мутирование с помощью простой функции расширения:
вы можете написать расширение функции для Котлина, которые делают на месте изменяемую итерацию для любого MutableList реализация.  Эти встроенные функции будут выполняться так же быстро, как любое пользовательское использование итератора, и встроены для производительности.  Идеально подходит для Android или где угодно.
здесь mapInPlace функция расширения (которая сохраняет именование, типичное для этих типов функций, таких как map и mapTo): 
inline fun <T> MutableList<T>.mapInPlace(mutator: (T)->T) {
    val iterate = this.listIterator()
    while (iterate.hasNext()) {
        val oldValue = iterate.next()
        val newValue = mutator(oldValue)
        if (newValue !== oldValue) {
            iterate.set(newValue)
        }
    }
}
пример вызов любого варианта этого расширения функция:
val someList = arrayListOf(1, 20, 10, 55, 30, 22, 11, 0, 99)
someList.mapInPlace { if (it <= 20) it + 20 else it }
это не обобщено для всех Collection<T>, потому что большинство итераторов только remove() способ, а не set().
функции расширения для массивов
вы можете обрабатывать общие массивы с помощью аналогичного метода:
inline fun <T> Array<T>.mapInPlace(mutator: (T)->T) {
    this.forEachIndexed { idx, value ->
        mutator(value).let { newValue ->
            if (newValue !== value) this[idx] = mutator(value)
        }
    }
}
и для каждого из примитивных массивов, использовать вариант:
inline fun BooleanArray.mapInPlace(mutator: (Boolean)->Boolean) {
    this.forEachIndexed { idx, value ->
        mutator(value).let { newValue ->
            if (newValue !== value) this[idx] = mutator(value)
        }
    }
}
об оптимизации с использованием только ссылочного равенства
функции расширения выше оптимизируют немного, не устанавливая значение, если оно не изменилось на другой экземпляр, проверяя, что с помощью === или !== is Равенство Ссылок.  Это не стоит проверять equals() или hashCode() потому что вызов этих имеет неизвестную стоимость, и действительно ссылочное равенство улавливает любое намерение изменить значение.  
модульные тесты для функций расширения
вот единичные тесты, показывающие рабочие функции, а также небольшое сравнение с функции stdlib map() это делает копию:
class MapInPlaceTests {
    @Test fun testMutationIterationOfList() {
        val unhappy = setOf("Sad", "Angry")
        val startingList = listOf("Happy", "Sad", "Angry", "Love")
        val expectedResults = listOf("Happy", "Love", "Love", "Love")
        // modify existing list with custom extension function
        val mutableList = startingList.toArrayList()
        mutableList.mapInPlace { if (it in unhappy) "Love" else it }
        assertEquals(expectedResults, mutableList)
    }
    @Test fun testMutationIterationOfArrays() {
        val otherArray = arrayOf(true, false, false, false, true)
        otherArray.mapInPlace { true }
        assertEquals(arrayOf(true, true, true, true, true).toList(), otherArray.toList())
    }
    @Test fun testMutationIterationOfPrimitiveArrays() {
        val primArray = booleanArrayOf(true, false, false, false, true)
        primArray.mapInPlace { true }
        assertEquals(booleanArrayOf(true, true, true, true, true).toList(), primArray.toList())
    }
    @Test fun testMutationIterationOfListWithPrimitives() {
        val otherList = arrayListOf(true, false, false, false, true)
        otherList.mapInPlace { true }
        assertEquals(listOf(true, true, true, true, true), otherList)
    }
}