Colton Idle
08/30/2023, 12:54 PMfor (i in list.indices) or should i do for(i in 0 .. list.size) or for(i in 0 until list.size) etc. I know it sounds dumb/basic. but anyone have any tricks they use to remember these. I feel like i should use the .. or until version of a for loopJohann Pardanaud
08/30/2023, 12:56 PMfor (item in list)?Johann Pardanaud
08/30/2023, 12:57 PMVampire
08/30/2023, 12:58 PMlist.forEach *{ ... }*Vampire
08/30/2023, 12:59 PMlist.forEachIndexed { ... }ascii
08/30/2023, 12:59 PMforEachIndexed or list.withIndex() for normal for loops. That's more _kotlin_; anything else reduces readability imo
Also, some colleagues of mine still get momentarily confused with .. and until. We found it easier to just avoid it whenever possible.Colton Idle
08/30/2023, 1:01 PMColton Idle
08/30/2023, 1:02 PMfun twoNumberSum(array: MutableList<Int>, targetSum: Int): List<Int> {
for (i in 0 until array.size - 1) {
val firstNum = array[i]
for (j in i + 1 until array.size) {
val secondNum = array[j]
if (firstNum + secondNum == targetSum) {
return listOf<Int>(firstNum, secondNum)
return listof<Int>()
}Colton Idle
08/30/2023, 1:03 PMi in 0 until array.size - 1
and
j in i + 1 until array.size
why not use ..Colton Idle
08/30/2023, 1:03 PMAyfri
08/30/2023, 1:03 PMfor loops and only forEach/forEachIndexedColton Idle
08/30/2023, 1:03 PMAyfri
08/30/2023, 1:03 PMj in 0..<array.size, the new until operator is made for that kind of loops !ascii
08/30/2023, 1:04 PMbreak out of forEach though (return@forEach is continue), without using an outer labelAyfri
08/30/2023, 1:05 PMWout Werkman
08/30/2023, 1:13 PM..<, which is arguably more conciseRafs
08/30/2023, 1:14 PMAdam S
08/30/2023, 1:15 PMuntil means ≤ or <. IntelliJ adds some helpful hints.Wout Werkman
08/30/2023, 1:26 PMWout Werkman
08/30/2023, 1:53 PMn*n operations to n*n / 2. But I would say that you can always start simple. My collection of leetcode util functions for example has a combinations function. Which gives the combination of all options between 2 iterables.
I could use this to solve the twoNumberSum problem.
fun twoNumberSum(array: MutableList<Int>, targetSum: Int): List<Int> {
return array.withIndex().combinations(array.withIndex())
.filter { (left, right) -> left.index != right.index }
.firstOrNull { (left, right) -> left.value + right.value == targetSum }
?.let { (left, right) -> listOf(left.index, right.index) }
?: throw AssumptionBrokenException(assumption = "Only one valid answer exists")
}
And you might worry about the performance, because this example does not have your / 2 optimization. But both of our implementations have O(N) performance.
To really gain performance, you need to think about the right algorithm. And in this case it's actually that you can utilize a lookup table like shown in the following example:
fun twoNumberSum(array: MutableList<Int>, targetSum: Int): List<Int> {
val searchingValuesToIndex = array.withIndex().associate { (targetSum - it.value) to it.index }
array.forEachIndexed { index, value ->
val indexOfMatchingValue = searchingValuesToIndex[value] ?: return@forEachIndexed
if (indexOfMatchingValue != index) return listOf(index, indexOfMatchingValue)
}
throw AssumptionBrokenException(assumption = "Only one valid answer exists")
}
This will have O(N) performance.
If you skipped it all, remember this:
Most interviewers will appreciate it if you can solve the problem without needlessly fiddling with indexes.ephemient
08/30/2023, 1:53 PMfor ((i, item) in list.withIndices))
to avoid the construction of an unnecessary wrapper iterator, and even if it didn't, it would be the clearer way to write it anywayephemient
08/30/2023, 1:54 PMVampire
08/30/2023, 2:00 PMfor ((i, item) in list.withIndices)) { ... } is clearer than
list.forEachIndexed { i, item -> ... }?ephemient
08/30/2023, 2:06 PMephemient
08/30/2023, 2:07 PMbreak and continue which do not with the functional extensionephemient
08/30/2023, 2:07 PM.forEach* at the end of a nullable or long chainJohann Pardanaud
08/30/2023, 2:09 PMfor loops are often more readable than many functional constructs. If you think it is not readable enough, remember destructuring is not mandatory and can sometime affect readability.Johann Pardanaud
08/30/2023, 2:10 PMforEach is great when you have a function to provide to it, but instead of using lambdas with it I prefer switching to a for loopLandry Norris
08/30/2023, 2:18 PMchunked, windowed, and other collection methods. They often make your code cleaner, shorter, and more idiomatic, at the cost of having to memorize them.Francesc
08/30/2023, 4:26 PMarray.size - 1 consider instead array.lastIndexColton Idle
08/30/2023, 8:20 PMfor (i in 0 until array.size - 1) {
val firstNum = array[i]
for (j in i + 1 until array.size) {
val secondNum = array[j]
using forEach? I thought if I need to "offset" my iterators then I kinda have no choice but to use the "primitive" version of a for loop instead of a functional forEach call.Landry Norris
08/30/2023, 8:23 PMarray.forEachIndexed { first, i ->
array.drop(i).forEach { second ->
...
}
}Francesc
08/30/2023, 8:34 PMdrop call makes a new Landry Norris
08/30/2023, 8:40 PMFrancesc
08/30/2023, 8:45 PMLandry Norris
08/30/2023, 8:50 PMFrancesc
08/30/2023, 8:53 PMLandry Norris
08/30/2023, 9:01 PMarray.mapIndexed { first, i ->
array.drop(i).sumOf { it + first }
}.sum()
Or
array.mapIndexedNotNull { first, i ->
array.drop(i).firstOrNull { it matches some condition }
}.first()
Or some other simplification.ephemient
08/31/2023, 12:20 AMdrop,
for ((i, first) in list.withIndices()) {
for (second in list.subList(i + 1)) {
gets there without excessive copying