https://kotlinlang.org logo
#getting-started
Title
# getting-started
c

Chetan Tuteja

12/27/2021, 7:19 AM
Hi guys! Quick question. Let us say I have a string array and I have another variable and I am just checking if that variable is in the array. I can directly use the
in
check for that. Is there any way to do the same check while ignoring case check? I know I can do the
any
check, anything besides that?
Copy code
val abc = "abc"
val random = arrayOf("ABC", "egf")

val isThere = abc in random // Prints false
e

ephemient

12/27/2021, 7:30 AM
Copy code
random.any { abc.equals(it, ignoreCase = true) }
c

Chetan Tuteja

12/27/2021, 7:31 AM
Yes, I was just updating the question with this. Is there a more elegant way than this?
e

ephemient

12/27/2021, 7:44 AM
doesn't seem like Kotlin (or Java for that matter) has any built-in case-folding operations, so in the general case that's probably as good as you can get without additional libraries
c

Chetan Tuteja

12/27/2021, 7:47 AM
I see. Maybe I can create an extension function around it to clean up the code around it @ephemient Something like this maybe. I can't come up with a good name though lol
Copy code
fun String.isIgnoreCasePresentIn(input: Array<String>): Boolean {
    return input.any { inp -> inp.equals(this, ignoreCase = true) }
}
e

ephemient

12/27/2021, 7:49 AM
abc.lowercase() in random.map { it.lowercase() }
,
abc.uppercase() in random.map { it.uppercase() }
, and even
abc.uppercase().lowercase() in random.map { it.uppercase().lowercase() }
will not be quite right for some inputs in some locales (this is where a proper Unicode casefold would be useful), but for most inputs something like that will likely work. if you're doing many membership tests with the same collection, you will probably be better off doing that with a
Set
i

ishwar verma

12/27/2021, 9:43 AM
isThere = random.find{it.equals(“abc”, true)}!=null
a

archecraft

12/27/2021, 10:33 AM
I would just create a wrapper class that only has a contains method that ignores case and you could just do something like this:
isThere = abc in random.ignoringCase()
. Would still require to use e.g. the
any
check, but would look nicer on the use side
m

MrNiamh

12/27/2021, 10:36 AM
I’m not seeing the isue with Ephemient’s first answer? It reads like English “are there any where abc equals an element (ignoring the case)” I wouldn’t overcomplicate it
c

Chetan Tuteja

12/27/2021, 10:39 AM
Yeah. I followed that and just created an extension function around it, to hide the unnecessary details. This was just an example. In the actual code there is some boilerplate for fetching the particular array to so overall it was a bit tough to read. Hid that under extension function. I guess it will do for now
👍 1
e

ephemient

12/27/2021, 11:26 AM
as I said earlier, if you're doing many checks with the same check, it would be better to case fold once - then you can use normal string comparison on the results. using ICU4J,
Copy code
val caseFold = CaseMap.fold()
val randomCaseFolded = buildSet { random.mapTo(this) { caseFold.apply(it) } }
caseFold.apply(abc) in randomCaseFolded
but
.lowercase()
or
.uppercase()
works if only have ASCII inputs and
.uppercase().lowercase()
should work for most other than Turkic languages
s

Shawn

12/27/2021, 4:09 PM
I think if this is a sort of comparison you’re doing often, you might want to optimize on the data structure side of things rather than the input side:
Copy code
val caseInsensitiveSet = TreeSet(String.CASE_INSENSITIVE_ORDER)
    .apply { addAll(setOf("ABC", "egf")) }

"abc" in caseInsensitiveSet  // true
The caveats relating to locale-specific rules on case still apply, though
java.text.Collator
has provisions for locale-aware logic. Also, yes, this particular solution is Java-specific, but I think the approach itself holds across platforms.
🆒 1
1
e

ephemient

12/28/2021, 12:21 AM
TreeSet is O(log n) lookup vs O(1) for most other sets (including
buildSet()
), but it's probably the best option if you need other collations
a

Arxing Lin

12/28/2021, 8:15 AM
just implement the operator function like that:
Copy code
fun main() {
  val abc = "abc"
  val random = arrayOf("ABC", "egf")

  println(abc in random) // return true
}

operator fun Array<String>.contains(element: String): Boolean = any {
  it.equals(element, true)
}
c

Chetan Tuteja

12/28/2021, 8:37 AM
@Arxing Lin That is a good suggestion. Although it can cause quite some confusion. Since it'd make every check case insensitive by default. I hope I am making sense.
a

Arxing Lin

12/28/2021, 8:55 AM
you can try
infix
functions like that:
Copy code
fun main() {
  val abc = "abc"
  val random = arrayOf("ABC", "egf")

  println(abc ignoreCaseIn random) // return true
}

infix fun String.ignoreCaseIn(array: Array<String>): Boolean = array.any {
  it.equals(this, true)
}
👌 1
c

Chetan Tuteja

12/28/2021, 9:55 AM
Awesome. Thank you!
2 Views