Kotlin: загрузить dict (hashmap), который содержит String и Tuple из файла - PullRequest
1 голос
/ 03 февраля 2020

Привет, коллеги-программисты,

Недавно я перешел с обычного python программирования на Kotlin программирование в Android Studio.

В python Я создал несколько словарей, которые содержат строки в качестве ключей и кортежи в качестве значений. Сами эти кортежи содержат int, две строки и снова два int. Представьте себе этот упрощенный диктат:

dict = {"key" : (1,"firstString","secondString",2,0),
        "secondKey":(0,"firstString","secondString",4,1)}

Теперь самое страшное: я хотел бы импортировать мои дикты в нормальные переменные / значения в Kotlin.

Поэтому я ставлю все четыре дикта. есть в текстовом файле в папке res. Для меня трудность заключается в том, чтобы одновременно объявить val соответствующей структуры данных и затем шаг за шагом загрузить пары ключ-значение в val. Кажется, что все Kotlin учебные пособия заканчиваются, когда мы углубляемся в их структуры данных.

Прав ли я, полагая, что у меня должна быть хеш-карта для самих диктов, а затем список (n-массив) для кортежи? Застрял даже при попытке объявить эту сложную структуру:

val importedDict: HashMap<String,Array<Integer,String,String,Integer>> = hashMapOf<String,Array<Int,String,String,Int>()

, поскольку в Kotlin.

просто не было допустимой структуры данных нескольких типов. Я благодарен за любую подсказку, которую вы можете дать.

Ответы [ 2 ]

2 голосов
/ 03 февраля 2020

Я считаю, что самый простой способ представить ваши кортежи - это объявить data class, например:

data class TupleData(val id: Int, 
                     val firstString: String, 
                     val secondString: String, 
                     val otherNumber: Int, 
                     val anotherNumber: Int)

, а затем объявить вашу структуру данных как HashMap<String, TupleData>. Обратите внимание, что вам нужно подумать об обнуляемости типов (String или String?) и о том, имеют ли они неизменные ссылки (val или var), поскольку вы не указали их в своем вопросе.

Кроме того, я думаю, что для облегчения вашей жизни вы можете использовать Moshi с настраиваемым адаптером для анализа вашей строки, как если бы это был JSON объект непосредственно в ваших структурах данных. (но имейте в виду этот другой ответ ).

Вы не можете объявить Array как Array<Integer, String, String, Integer>, поскольку он принимает только один универсальный c параметр с именем T в kotlin документация . Если вы хотите указать кортеж, вы должны использовать Pair или Triple , и если в кортеже больше данных, то объявите data class


РЕДАКТИРОВАТЬ: Попытавшись создать рабочий пример с вашими данными, я заметил, что они неправильно отформатированы для анализа JSON, поэтому вам, вероятно, придется анализировать их вручную.

Если вы все еще хотите разобраться, как сериализовать в JSON (возможно, используя pickle из Python), вот как я реализовал адаптер:

class TupleDataAdapter {
    @ToJson
    fun toJson(tupleData: TupleData) : String {
        val (id, first, second, other, another) = tupleData;
        return "($id, $first, $second, $other, $another)" 
    }

    @FromJson
    fun fromJson(tuple: String) : TupleData {
        if (tuple[0] != '(' || tuple.last() != ')') {
            throw JsonDataException("Wrong format for tuple data: missing '(' or ')'")
        }

        val trimmed = tuple.trimStart('(').trimEnd(')')
        val fields = trimmed.split(',')
        if (fields.size != 5) {
            throw JsonDataException("Wrong format for tuple data: wrong number of fields in tuple")
        }
        return TupleData(fields[0].toInt(), fields[1], fields[2], fields[3].toInt(), fields[4].toInt()) 
    }
}

fun main(args: Array<String>) {

    val dict = File("./dict.txt").readText()

    println(dict)

    val moshi = Moshi.Builder()
        .add(TupleDataAdapter())
        .build()

    val type = Types.newParameterizedType(Map::class.java, String::class.java, TupleData::class.java)   

    val mapAdapter : JsonAdapter<Map<String, TupleData>> = moshi.adapter(type)
    val decoded : Map<String, TupleData>? = mapAdapter.fromJson(dict)

    println(decoded)
}

Эта реализация работала правильно, когда я изменил текст как таковой:

{"key" : "(1,firstString,secondString,2,0)","secondKey" : "(0,firstString,secondString,4,1)"}

Обратите внимание на разницу в кавычках.

1 голос
/ 03 февраля 2020

Массив может содержать только один тип данных, поэтому вместо него нельзя объявить несколько типов, используйте Array<Any>, где Любой - это суперкласс каждого объекта, поэтому используйте

  var map : Map<String, Array<Any>> = mapOf("key" to arrayOf(1,"firstString","secondString",2,0))

. Вы можете объявите массив, если вы хотите добавить такие значения, как

  var map2 : HashMap<String, Array<Any>> = HashMap<String, Array<Any>>()
  map2.put("key" , arrayOf(1,"firstString","secondString",2,0))
  println(map2["key"]?.get(2)) // "secondString"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...