ferrytan
04/23/2019, 3:49 AM[
{"A",1},
{"A",1},
{"A",1},
{"B",1},
{"C",1},
{"D",1},
{"D",1},
{"A",1},
{"A",1},
{"D",1}
]
I'm aiming to merge the adjacent items and add the integer value for each adjacent items, the end result should transform as this:
Result: [
{"A",3},
{"B",1},
{"C",1},
{"D",2},
{"A",2},
{"D",1}
]
I've searched through basic extensions for Collection, closest i can found is using windowed
with step
1 and size
1, but it seems like i have to loop and map the call multiple times until there are no pairs to get the result i wanted.
Is there any other way to get around this?
I also tried zipWithNext
but it gets tricky if there are more than 2 adjacent items on the listyen
04/23/2019, 5:41 AMlist.groupBy { ... }
Alowaniak
04/23/2019, 5:44 AMfold
work though?
https://pl.kotl.in/FYrYZ9Zxgpindab0ter
04/23/2019, 7:55 AMlist.groupBy { … }
won’t work because it doesn’t preserve separated groups.
list.groupingBy { … }
does, but when I tried to implement a solution with it it quickly became more complex than the fold
@Alowaniak posted.ribesg
04/23/2019, 8:09 AMwindowed
karelpeeters
04/23/2019, 8:13 AMstellarspot
04/23/2019, 8:43 AMfun <Key> List<Pair<Key, Int>>.countAdjacent(): List<Pair<Key, Int>> {
val res = mutableListOf<Pair<Key, Int>>()
if (this.isEmpty()) {
return res
}
var key = this.first().first
var count = this.first().second
this.forEachIndexed { index, pair ->
if (index != 0) {
if (pair.first == key) {
count += pair.second
} else {
res.add(Pair(key, count))
key = pair.first
count = pair.second
}
}
}
res.add(Pair(key, count))
return res
}
fun <Key> List<Pair<Key, Int>>.countAdjacent(): List<Pair<Key, Int>> {
val res = mutableListOf<Pair<Key, Int>>()
var key: Key? = null
var count = 0
this.forEach { pair ->
if (pair.first == key) {
count += pair.second
} else {
if (key != null) {
res.add(Pair(key!!, count)) // Compilation error if !! is not used with key
}
key = pair.first
count = pair.second
}
}
if (key != null) {
res.add(Pair(key!!, count)) // Compilation error if !! is not used with key
}
return res
}
pindab0ter
04/23/2019, 9:31 AMfun <T> List<Pair<T, Int>>.countAdjacent(): List<Pair<T, Int>> = fold(emptyList()) { acc, e ->
acc.lastOrNull()
?.takeIf { it.first == e.first }
?.let { acc.dropLast(1).plus(it.first to it.second + e.second) }
?: acc.plus(e)
}
ribesg
04/23/2019, 9:34 AMArrayList
instances to you create with a single function call there? I would be the kind of guy to implement this on MutableList
and attempt to do it in place and in O(n)
with a MutableIterator
. But I guess it depends on the use case. If you know that you’ll have at most 30 items in your list, immutability is the way to godata class Entry<T>(val value: T, var count: Int)
fun <T> MutableList<Entry<T>>.countAdjacent(): MutableList<Entry<T>> {
if (size <= 1) return this
val iterator = listIterator()
var previous = iterator.next()
do {
val current = iterator.next()
if (current.value == previous.value) {
previous.count++
iterator.remove()
}
previous = current
} while (iterator.hasNext())
return this
}
ferrytan
04/23/2019, 10:46 AMfold
works perfectly, i have around 250+ data and it took around 70ms to fold the collection. fast enough, and my data count won't be higher than that, so i guess the fold
method fits my requirement 👍🏻
The extension function is awesome @pindab0ter, thank you so much!
gets amazed even more by `kotlin`'s cleanliness
although the suggestion from @stellarspot @ribesg might be preferable if i have a very huge data count.
Anyway, thank you guys for the answers!
solved my problem🙏karelpeeters
04/23/2019, 6:16 PM70 ms
just to do some trivial operation? That kind of stuff adds up quickly 😕pindab0ter
04/23/2019, 8:52 PMAlowaniak
04/23/2019, 10:43 PMapply
which makes it look a bit nicer IMHO (I don't like the trailing acc) but ymmv, it can get confusing because you're basically having multiple receivers
fun <T> List<Pair<T, Int>>.sumAdjacentFoldMutable() = fold(mutableListOf<Pair<T, Int>>()) { acc, e ->
acc.apply {
if (lastOrNull()?.first == e.first) set(lastIndex, e.first to e.second + last().second)
else add(e)
}
} //as List<Pair<T, Int>>
ferrytan
04/24/2019, 10:55 AMsumAdjacentFoldMutable took 267ms
sumAdjacentFoldImmutable took 10496ms
countAdjacentImperative took 142ms