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/forEachIndexed
Colton 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.lastIndex
Colton 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