Home > Enterprise >  Convert String to Map Kotlin
Convert String to Map Kotlin

Time:03-18

I´m trying to convert this Kotlin string below to map for removing duplicates names and also remove all the email entry.

var str: String = "name=John Trust, username=john3, [email protected], id=434453; name=Hannah Smith, username=hsmith, [email protected], id=23312; name=Hannah Smith, username=hsmith, id=3223423, [email protected];"

My code generates a error:

  val array = log_dump.split(";")
  var map = emptyMap<String, String>()
  for (a in array) {
    map = a.split(",").associate { 
    val (left, right) = it.split("=")
    left to right.toString() 
    }
  }
  println(map)

CodePudding user response:

here is how you can do it, first change the log_dump to str, since you want to split that, and second thing, you have to remove the last ";" since you don't need that, for me I just check if it is the null or empty string then continue meaning skip this.

fun main() {
    
    var str: String = "name=John Trust, username=john3, [email protected], id=434453; name=Hannah Smith, username=hsmith, [email protected], id=23312; name=Hannah Smith, username=hsmith, id=3223423, [email protected];"
    val array = str.split(";")
    var map = emptyMap<String, String>()
    
    for (a in array) {
        if(a == ""){
            continue
        }
        map = a.split(",").associate { 
            val (left, right) = it.split("=")
            left to right.toString() 
        }
    }
    println(map)
    
}

Here is how you get all users.

fun main() {
    
    var str: String = "name=John Trust, username=john3, [email protected], id=434453; name=Hannah Smith, username=hsmith, [email protected], id=23312; name=Hannah Smith, username=hsmith, id=3223423, [email protected];"
    val array = str.split(";")
    var map = emptyMap<String, String>()     
    var allUsers = mutableMapOf<Int, MutableList<Pair<String, String>>>()    
   
    
    var count: Int = 0;
    for (a in array) {
        count  = 1
        if(a == ""){
            continue
        }
        map = a.split(",").associate { 
            
            val (left, right) = it.split("=")
            allUsers.getOrPut(count) { mutableListOf() }.add(Pair(left.toString(), right.toString() ))     
            left to right.toString()               
        }             
               
                        
    }
    println(allUsers)
    // get the first user info
    println(allUsers[1])
}

I am using an online compiler here so let me know if anything goes wrong.

// Output: { name=Hannah Smith, username=hsmith, id=3223423, [email protected]}

CodePudding user response:

The uniqueness constraint is not well defined, do you want to keep the first, last something else? Apart from uniqueness though here is a solution (online demo here) :

data class User(val name: String, val userName: String, val email: String, val id: String)

fun String.cleanSplit(token: String) = this.split(token).map { it.trim() }.filter { it.isNotEmpty() }
fun String.asUserRows() = cleanSplit(";")
fun String.asUser(): User = let {
    val attributeMap = this.cleanSplit(",").map { it.cleanSplit("=") }.associate { it[0] to it[1] }
    User(attributeMap["name"]!!, attributeMap["username"]!!, attributeMap["email"]!!, attributeMap["id"]!!)
}

fun main() {
    val str: String =
        "name=John Trust, username=john3, [email protected], id=434453; name=Hannah Smith, username=hsmith, [email protected], id=23312; name=Hannah Smith, username=hsmith, id=3223423, [email protected];"

    val users: List<User> = str.asUserRows().map { it.asUser() }.also { println(it) }
    // at this point you can enforce uniqueness on users
    // for example this code will have list of users with unique name keeping the last one
    users.associateBy { it.name }.values.also { println(it) }
}
}

CodePudding user response:

As Karsten Gabriel said you got an error is because of empty string and also you are overriding users

I understand your question like you want to remove email fields and make data distinct by user.name.

If you want the end result to be string you can do it without maps

val log_dump: String =
    "name=John Trust, username=john3, [email protected], id=434453; name=Hannah Smith, username=hsmith, [email protected], id=23312; name=Hannah Smith, username=hsmith, id=3223423, [email protected];"

val commaRegex = Regex("\\s*,\\s*")
val semicolonRegex = Regex("\\s*;\\s*")

val sanitizedLogDump = log_dump.split(semicolonRegex).asSequence()
    .mapNotNull { userString ->
        var name: String? = null
        val filteredUserFieldString = userString.split(commaRegex) // split by "," and also omit spaces
            .filter { fieldString -> // filter field strings not to include email
                val keyVal = fieldString.split("=")

                // check if array contains exactly 2 items
                if (keyVal.size == 2) {
                    // look for name
                    if (keyVal[0] == "name") {
                        name = keyVal[1]
                    }
                    // omit email fields
                    keyVal[0] != "email" // return@filter
                } else {
                    false // return@filter
                }
            }
            .joinToString(separator = ", ") // join field back to string
        // omit fieldString without name and add ; to the end of fieldString
        if (name == null) null else Pair(name, "$filteredUserFieldString;") // return@mapNotNull
    }
    .distinctBy { it.first } // distinct by name
    .joinToString(separator = " ") { it.second }

println(sanitizedLogDump)

However, if you still want the end result to be map


val log_dump: String =
    "name=John Trust, username=john3, [email protected], id=434453; name=Hannah Smith, username=hsmith, [email protected], id=23312; name=Hannah Smith, username=hsmith, id=3223423, [email protected];"

val commaRegex = Regex("\\s*,\\s*")
val semicolonRegex = Regex("\\s*;\\s*")

val usersMap = log_dump.split(semicolonRegex).asSequence()
    .mapNotNull { userString ->
        var name: String? = null
        val userFieldsMap = userString.split(commaRegex) // split by "," and also omit spaces
            .mapNotNull { fieldString -> // filter field strings not to include email and map it to pairs
                val keyVal = fieldString.split("=")
                // check if array contains exactly 2 items
                if (keyVal.size == 2) {
                    // look for name
                    if (keyVal[0] == "name") {
                        name = keyVal[1]
                    }
                    // omit email fields
                    if (keyVal[0] != "email") keyVal[0] to keyVal[1] else null // return@filter
                } else {
                    null // return@filter
                }
            }

        // omit fieldsMap without name
        if (name == null) null else Pair(name, userFieldsMap) // return@mapNotNull
    }
    .toMap()

CodePudding user response:

There are a few small mistakes in your code:

  1. You get an error because the split also yields an empty string which has to be filtered out.
  2. You overwrite your result map on each iteration, instead of saving the complete result.
  3. You should trim your result keys to remove unwanted leading or trailing spaces (e.g. to obtain username instead of username).
var str: String = "name=John Trust, username=john3, [email protected], id=434453; name=Hannah Smith, username=hsmith, [email protected], id=23312; name=Hannah Smith, username=hsmith, id=3223423, [email protected];"

val array = str.split(";").filterNot { it.isEmpty() } // 1. filter out non-empty strings
var map = array.map { // 2. use map instead of a for-loop
    it.split(",").associate {
        val (left, right) = it.split("=")
        left.trim() to right.toString() // 3. trim keys
    }
}
  • Related