14

I have two strings

val string1 = "Hello"
val string2 = "Hello world"

I have to count existence of each letter from string1 in string2 in Kotlin

So far, I have written this much code and stuck with regex

val string1_array = string1.toCharArray()
val pattern = Regex("") // Regex pattern here
val matcher = string2

val count = pattern.findAll(matcher).count()

What should be the appropriate Regex pattern to search for charArray? Is there some better way to do in Kotlin

Andrey Tyukin
  • 38,712
  • 4
  • 38
  • 75
Anuj TBE
  • 6,408
  • 15
  • 85
  • 199
  • 1
    You don't need any regex to count characters in a string. Just use a loop (or any other kind of iteration). – JB Nizet Apr 15 '18 at 20:11
  • Could you add your expected logic please? – jrtapsell Apr 16 '18 at 00:17
  • Do you need to count each char separately? E.g. how many times you have 'H', how many times 'e' and so on? – stan0 Apr 16 '18 at 09:50
  • 2
    Here's a 1 line solution using Kotlin's collection functions: val occurrences = string2.filter{ it in string1} .groupingBy { it } .eachCount() – hexkid Apr 16 '18 at 21:08

6 Answers6

16

Here are some String extension functions you can use

Occurrences of any char

With the fold extension function:

val string1 = "Hello"
val string2 = "Hello world Hello"

print(
     string2.fold(0) {
         sum: Int, c: Char ->
         if (string1.contains(c))
             sum + 1
         else
             sum
     }   
) 

Or even shorter with sumBy:

string2.sumBy { 
    if (string1.contains(it))
        1
    else
        0
}

And shortest:

string2.count{ string1.contains(it) }

Occurrences of each char individually

With forEach and a MutableMap:

val charsMap = mutableMapOf<Char, Int>()

string2.forEach{
    charsMap[it] = charsMap.getOrDefault(it, 0) + 1
}

print(charsMap)

Occurrences of the whole string1

With the windowed extension function:

string2.windowed(string1.length){
    if (it.equals(string1))
        1
    else
        0
}.sum()

You can browse more String extension functions in the String stblib page

stan0
  • 10,239
  • 5
  • 41
  • 57
  • 1
    Shouldn't it be `sum +1`and `sum` as returns? – leonardkraemer Apr 16 '18 at 09:58
  • @leoderprofi absolutely! Forgot them. I'll add a map variant for each char shortly too – stan0 Apr 16 '18 at 10:05
  • 1
    Nice use of windowed when searching for the whole string! I slightly prefer to do that like this: `string2.windowed(string1.length).filter { it == string1 }.count()` – Matt Mar 01 '19 at 01:10
  • 3
    This should have been the accepted answer imho, thank you for introducing me to windowed, I'm new to Kotlin/FP. – Marco Sep 23 '19 at 13:18
12

Just use Kotlin's collection functions

val occurrences = string2.filter{ it in string1}
                        .groupingBy { it }
                        .eachCount()
hexkid
  • 494
  • 1
  • 4
  • 12
8

You can use the below higher order method,

val count = string2.count{ string1.contains(it) }
print(count)
Kamran
  • 13,636
  • 3
  • 26
  • 42
4

Simplified use case when you only want to count occurrences of a single character:

println("needle in a haystack".count{ c -> c == 'a' })
// OUTPUT: 3

Reference:

ccpizza
  • 21,405
  • 10
  • 121
  • 123
0

You can use chars from the first string as map keys, for example:

val string1 = "Hello"
val string2 = "Hello world"

val chars = HashMap<Character, Int>()

for (char in string1) // fill keys
    chars[char] = 0

for (char in string2) // count occurrences
    chars[char]?.let {
        chars[char] = it + 1
    }
Miha_x64
  • 4,532
  • 1
  • 35
  • 56
0

To answer actual the question: the simplest regex pattern would be to use a character class syntax "[" + string1 + "]". Beware, this is not always well behaved. It works well for all ASCii letters and numbers. Special characters like \^-?! must be properly escaped. For the rules see https://www.regular-expressions.info/charclass.html

fun main(args: Array<String>): Unit {
    val string1 = "Hello"
    val string2 = "Hello world Hello"

    val string1_array = string1.toCharArray()
    val pattern = Regex("[" + string1 + "]") // Regex pattern here
    val matcher = string2

    val count = pattern.findAll(matcher).count()
    print(count)
}

How to solve the task: Imho the best way to do this task is to use filter or count instead of regex, because the you don't have to use any special syntax.

fun main(args: Array<String>): Unit {
        val string1 = "Hello"
        val string2 = "Hello world Hello"
        //returns all chars of string2 contained in string1 as list
        val count = string2.filter { string1.contains(it) }.length
        //an other a bit shorter solution with count
        count = string2.count{ string1.contains(it) }
        print(count)
}
leonardkraemer
  • 5,372
  • 1
  • 21
  • 44