2

I have a

val map = Map<String,String>
map.put("Nurseiyt","android")

I want to get a value by subString like:

map["Nurs"] should return "android"

is it possible?

Nurseyit Tursunkulov
  • 8,012
  • 12
  • 44
  • 78
  • No, not with a Map. – JB Nizet Aug 29 '19 at 06:22
  • 2
    you can seek for some workaround tho, like `map.filterKeys { it.contains("Nurs") }.values` which gives you collection of all values that match substring `Nurs` – P.Juni Aug 29 '19 at 06:33
  • You shouldn't do that kind of tricks with Maps. Otherwise you will have a collision with similar keys -- in case you have something like `map.put("Nurseiyt1","android")` and `map.put("Nurseiyt2","ios")` – Nikolai Shevchenko Aug 29 '19 at 06:51

3 Answers3

2

Use kotlin.Collections, there are methods like filter.

Two things - it's better to use regular expression. So, you can even get better control what will be returned. And the second one, there can be more than one elements matched to that regex. So that's why I return list.

fun <T> substringKey(map: Map<String, T>, regex: Regex): List<T> {
    return map.filter { it.key.contains(regex) }
        .map { it.value }
}

If you want to use that notation you need to create your own map and override proper operator. What's worth to notice, you cannot return list of values then. So, in this case I just return first found value.

class SubstringMap<V> : HashMap<String, V>() {
    override operator fun get(key: String): V? {
        return this.entries.first { it.key.contains(key) }.value
    }
}

fun main() {
    val map = SubstringMap<String>()
    map["Nurseiyt"] = "android"
    println(map["Nurs"]) // "android"
}

And as the last thing - in kotlin you can create your own operator, like withKeyPart. This would be much better than overriding default operator (because I wouldn't expect that [] operator will work in different way than usual.

infix fun <V> Map<String, V>.withKeyPart(keyPart: String): List<V> {
    return this.filter { it.key.contains(keyPart) }
        .map { it.value }
}

and then call it like this:

fun main() {
    val map = HashMap<String, String>()

    map withKeyPart "KeyPart" // infix notation
    map.withKeyPart("KeyPart") // standard call
}
Cililing
  • 4,303
  • 1
  • 17
  • 35
1

write top level function like this

fun HashMap<String, String>.getContainskeyValue(search: String): String? 
{
var returnList = ArrayList<String?>()
this.keys.filter { it.contains(search) }.map {
    returnList.add(this[it])
 }
return returnList.first()  

//if you want all keys 'contains' values just return list
/* Ex
map.put("Nurseiyt", "android")
map.put("Nurseiyt1", "androidone")
map.put("Nurseirt2", "andrrroidtwo")
val isContainsdata = map.getContainskeyValue("N")
println(" result " + containsdata)
output :result [andrrroidtwo, android, androidone]
*/
}

then call like this

val map = HashMap<String, String>()
map.put("Nurseiyt", "android")
val containsdata = map.getContainskeyValue("Nurs")
println(" result " + containsdata)

output

android
sasikumar
  • 12,540
  • 3
  • 28
  • 48
1

Filtering the map, as per other answers, is simple and straightforward, but it doesn't scale well; it takes time proportional to the size of the map, so if the map could grow big, it could get very slow.

If you're always going to be searching for a leading substring, i.e. the start of a map key, then a better general solution is a data structure called a trie.  This lets you search efficiently, with just one lookup per character.

Of course, writing one from scratch may not be justified for your project.  But there are third-party implementations you could use, such as this one in Apache Commons.  Or see the answers to this question.

gidds
  • 16,558
  • 2
  • 19
  • 26