Reputation: 389
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)
Upvotes: 0
Views: 3087
Reputation: 3662
There are a few small mistakes in your code:
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
}
}
Upvotes: 0
Reputation: 300
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()
Upvotes: 2
Reputation: 9086
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) }
}
}
Upvotes: 0
Reputation: 586
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]}
Upvotes: 0