Как преобразовать список в карту в Kotlin?

170

Например, у меня есть список строк, таких как:

val list = listOf("a", "b", "c", "d")

и я хочу преобразовать его в карту, где строки являются ключами.

Я знаю, что должен использовать эту .toMap()функцию, но я не знаю как, и я не видел ни одного примера.

LordScone
источник

Ответы:

319

У вас есть два варианта:

Первым и наиболее эффективным является использование associateByфункции, которая берет две лямбды для генерации ключа и значения и указывает на создание карты:

val map = friends.associateBy({it.facebookId}, {it.points})

Второй, менее производительный, заключается в использовании стандартной mapфункции для создания списка, Pairкоторый может быть использован toMapдля генерации окончательной карты:

val map = friends.map { it.facebookId to it.points }.toMap()
voddan
источник
1
Спасибо. это быстрее, потому что он создает карту, а не конвертирует список пар в карту, как в моем примере?
LordScone
4
@lordScone Точно, распределение Pairэкземпляров может быть очень дорогостоящим для больших коллекций
voddan
41

С Listпо Mapс associateфункцией

С Kotlin 1.3, Listесть функция под названием associate. associateимеет следующую декларацию:

fun <T, K, V> Iterable<T>.associate(transform: (T) -> Pair<K, V>): Map<K, V>

Возвращает Mapсодержащие пары ключ-значение, предоставленные transformфункцией, примененной к элементам данной коллекции.

Использование:

class Person(val name: String, val id: Int)

fun main() {
    val friends = listOf(Person("Sue Helen", 1), Person("JR", 2), Person("Pamela", 3))
    val map = friends.associate({ Pair(it.id, it.name) })
    //val map = friends.associate({ it.id to it.name }) // also works

    println(map) // prints: {1=Sue Helen, 2=JR, 3=Pamela}
}    

С Listпо Mapс associateByфункцией

С Kotlin, Listесть функция под названием associateBy. associateByимеет следующую декларацию:

fun <T, K, V> Iterable<T>.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V): Map<K, V>

Возвращает Mapсодержащий значения, предоставленные valueTransformи проиндексированные keySelectorфункциями, примененными к элементам данной коллекции.

Использование:

class Person(val name: String, val id: Int)

fun main() {
    val friends = listOf(Person("Sue Helen", 1), Person("JR", 2), Person("Pamela", 3))
    val map = friends.associateBy(keySelector = { person -> person.id }, valueTransform = { person -> person.name })
    //val map = friends.associateBy({ it.id }, { it.name }) // also works

    println(map) // prints: {1=Sue Helen, 2=JR, 3=Pamela}
}
Imanou Petit
источник
3
В чем разница между Associate и AssociateBy? Хотел бы я предпочесть использовать один над другим, видя, что они дают одинаковый результат?
Уэйнсфорд
11
  • Преобразовать элементы итерируемой последовательности в карту в kotlin,
  • Associate vs associateBy против associateWith:

* Ссылка: Kotlin Документация

1- связать (чтобы установить ключи и значения): построить карту, которая может установить элементы ключа и значения:

IterableSequenceElements.associate { newKey to newValue } //Output => Map {newKey : newValue ,...}

Если какая-либо из двух пар будет иметь одинаковый ключ, последняя добавляется на карту.

Возвращенная карта сохраняет порядок итераций входа исходного массива.

2- associateBy (просто установите ключи по расчету): создайте карту, в которой мы можем установить новые ключи, аналогичные элементы будут установлены для значений

IterableSequenceElements.associateBy { newKey } //Result: => Map {newKey : 'Values will be set  from analogous IterableSequenceElements' ,...}

3- associateWith (просто установите значения по расчету): создайте карту, в которой мы можем установить новые значения, аналогичные элементы будут установлены для ключей

IterableSequenceElements.associateWith { newValue }  //Result => Map { 'Keys will be set from analogous IterableSequenceElements' : newValue , ...}

Пример из советов Котлина: введите описание изображения здесь

Хамед Джалилиани
источник
10

Вы можете использовать associateдля этой задачи:

val list = listOf("a", "b", "c", "d")
val m: Map<String, Int> = list.associate { it to it.length }

В этом примере строки from listстановятся ключами, а их соответствующие длины (в качестве примера) становятся значениями внутри карты.

s1m0nw1
источник
7

Если в вашем списке есть дубликаты, которые вы не хотите терять, вы можете сделать это, используяgroupBy .

В противном случае, как и все остальные, используйте use associate/By/With(который, как я полагаю, в случае дубликатов вернет только последнее значение с этим ключом).

Пример группировки списка людей по возрасту:

class Person(val name: String, val age: Int)

fun main() {
    val people = listOf(Person("Sue Helen", 31), Person("JR", 25), Person("Pamela", 31))

    val duplicatesKept = people.groupBy { it.age }
    val duplicatesLost = people.associateBy({ it.age }, { it })

    println(duplicatesKept)
    println(duplicatesLost)
}

Полученные результаты:

{31=[Person@41629346, Person@4eec7777], 25=[Person@3b07d329]}
{31=Person@4eec7777, 25=Person@3b07d329}
cs_pupil
источник
0

Это изменилось в версии RC.

Я использую val map = list.groupByTo(destinationMap, {it.facebookId}, { it -> it.point })

Лагос
источник