Reputation: 7939
If I have the following array:
[1,1,1,2,2,1,1,1,1,2,2,3]
Is there any built in method in Kotlin which will filter out adjacent elements of the same value, resulting in:
[1,2,1,2,3]
It's important that the order is preserved.
P.S. My actual use case isn't integers, it's an object which implements equals.
Upvotes: 5
Views: 724
Reputation: 18547
There's a one-line solution, using zipWithNext()
:
list.zipWithNext().filter{ it.first != it.second }.map{ it.first } + list.last()
That creates a list of pairs of adjacent elements; we then filter out the identical pairs, and take the first of each remaining pair. That will have omitted the last one, so we have to add that in separately.
That works with any element type, using the object's own notion of equality (via its equals()
method); this includes nullable types (unlike another answer). And it's stateless so ‘pure’ functional (which you may or may not consider a good thing!).
It handles one-element lists, but not empty lists; for completeness, you'd have to handle those separately. And it would fit very neatly into an extension function:
fun <T> List<T>.compress() = when (isEmpty()) {
true -> listOf()
else -> zipWithNext().filter{ it.first != it.second }.map{ it.first } + last()
}
Upvotes: 4
Reputation: 6148
I don't think there is a standard function to do this.
But it is easy to build one with mapOrNull
:
fun <T : Any> Iterable<T>.removeAdjacent(): List<T> {
var last: T? = null
return mapNotNull {
if (it == last) {
null
} else {
last = it
it
}
}
}
Upvotes: 5
Reputation: 2039
Functional solution using fold
:
val result = listOf(1,1,1,2,2,1,1,1,1,2,2,3)
.fold(mutableListOf<Int>()) { currentList, currentItem ->
if (currentList.isEmpty()) { // Applies only to the very first item
mutableListOf(currentItem)
} else {
if (currentItem != currentList.last()) {
currentList.apply { add(currentItem) }
} else {
currentList
}
}
}
Upvotes: 3