collapse list of int to list of ranges in kotlin - collections

I have a list of ints that needs to be compressed to list of int ranges without loosing any information (there must be a way to reverse this operation).
Currently I have:
val ints = listOf(8, 9, 45, 48, 49, 60, 61, 61, 62, 63, 3, 4, 5, 4, 5, 6)
val out = ints
.map { it..it }
.fold(mutableListOf(ints[0]..(ints[0] - 1)),
{ acc, next ->
val prev = acc.last()
if (prev.last + 1 == next.first) {
acc[acc.lastIndex] = prev.first..next.last
} else {
acc.add(next)
}
acc
}).toList()
That correctly produces:
[8..9, 45..45, 48..49, 60..61, 61..63, 3..5, 4..6]
There are two aspects I dislike in my solution though,
it does not work for empty list because of fold's initial value
it's quite verbose for kotlin. I have a feeling that this can be resolved in bit nicer way.
So, the question is how to fix 1 and/or 2?
Thanks in advance!

Since you actually mutate the acc and return the same list of ranges at all iterations of fold, you may not really need the fold, that is, forEach is enough.
Then, mapping each number to it..it seems to be redundant here.
Taking the two notes above into account leads to the following, a bit simplified, version of your solution:
val result = mutableListOf<IntRange>()
ints.forEach {
val lastRange = result.lastOrNull()
if (lastRange?.endInclusive == it - 1)
result[result.lastIndex] = lastRange.first..it
else
result += it..it
}
UPD: with the addition of buildList to the Kotlin standard library, you can rewrite the above as:
val result = buildList {
ints.forEach {
val last = lastOrNull()
if (last?.endInclusive == it -1) {
set(lastIndex, last.start..it)
} else {
add(it..it)
}
}
}

My solution doesn't look much different, but I was able to fix your empty list issue:
val out = ints.fold(mutableListOf<IntRange>()) { acc, next ->
acc.apply {
if(isNotEmpty() && last().endInclusive.inc() == next) {
this[lastIndex] = this[lastIndex].start .. next
} else {
add(next..next)
}
}
}
It's also a bit less mapping, and using apply takes away some of the verbosity and having to refer to acc at the end.

Related

Invert Map<K, List<V>> to Map<V, K>

map = mapOf((2: [3,4,5]), (7: [22,33,44]))
need to convert this to
mapOf(3:2, 4:2, 5:2, 22:7, 33:7, 44:7)
tried using associate with forEach, not sure of the syntax
There might be some nicer syntax, but this should work well enough.
fun main() {
val map = mapOf(
2 to listOf(3, 4, 5),
7 to listOf(22, 33, 44)
)
val transformedMap = map.flatMap { entry ->
entry.value.map { it to entry.key }
}.toMap()
println(transformedMap)
}
Prints
{3=2, 4=2, 5=2, 22=7, 33=7, 44=7}
Note that the toMap function states
The returned map preserves the entry iteration order of the original collection. If any of two pairs would have the same key the last one gets added to the map.
So if you have the same value in two different lists, only the last one will be included in the map.
fun main() {
val map = mapOf(
2 to listOf(3, 4, 5),
7 to listOf(22, 33, 44),
8 to listOf(3)
)
val transformedMap = map.flatMap { entry ->
entry.value.map { it to entry.key }
}.toMap()
println(transformedMap)
}
Prints {3=8, 4=2, 5=2, 22=7, 33=7, 44=7}
Zymus' answer is correct, and is also what I would probably write.
However, if this is something that will be called often, you might want to extract it to a separate function that is more efficient.
fun <K, V> Map<K, Iterable<V>>.invert(): Map<V, K> {
val newMap = mutableMapOf<V, K>()
for ((key, iterable) in this) {
for (value in iterable) {
newMap[value] = key
}
}
return newMap
}
Usage:
fun main() {
val map = mapOf((2 to listOf(3, 4, 5)), (7 to listOf(22, 33, 44)))
val inverted = map.invert()
println(inverted)
}
Output:
{3=2, 4=2, 5=2, 22=7, 33=7, 44=7}
This is functionally equivalent to
map.flatMap { (key, values) -> values.map { it to key } }.toMap()
including the behaviour where if there are duplicate values in the original input, only the last one will be preserved as a new key. However, the flatMap version creates many temporary Lists (the number of original keys + 1) and many temporary Pairs (the number of original values), whereas this iterative version creates no extra objects.

How best to find an element in nested lists?

Kotlin provides some usingful extension functions allow stream-like programming.
For example, if I look for an element in a list I can use find:
return list.find { n -> n>4 && n<6 }
But when I have a have nested lists this seems not practical for me. I have tu use forEach then -- luckyly I can return from an inner Lambda with Kotlin:
private fun findUsingForEach(data: List<List<Int>>, pred : (Int) -> Boolean) : Optional<Int> {
data.forEach { list ->
list.forEach { n ->
if( pred(n) ) return Optional.of(n)
}
}
return Optional.empty()
}
It seems fo me that forEach is not the right tool for that. Is there a more functional way to du this? filter comes to mind, but the nesting causes problems.
That follwing is the test I use for the function abouve:
#Test
open fun findTest() {
val data = listOf( listOf(1,2,3), listOf(3,4,5,6), listOf(), listOf(6,7,8) )
val e = findUsingForEach( data, { n -> n>4 && n < 6 } )
assertEquals(5, e.get())
}
You could flatten the list:
fun <T> Iterable<Iterable<T>>.flatten(): List<T> (source)
Returns a single list of all elements from all collections in the given collection.
val data = listOf(listOf(1, 2, 3), listOf(3, 4, 5, 6), listOf(), listOf(6, 7, 8))
data.flatten().find { n -> n > 4 && n < 6 }
This will return a single list with the elements of the sublists in order. Then you can use find as usual.
In your example,
{{1, 2, 3}, {3, 4, 5, 6}, {}, {6, 7, 8}}
becomes
{1, 2, 3, 3, 4, 5, 6, 6, 7, 8}
and the result of find on this list is 5.
However, this will create a new list. Take a look at the source of flatten:
/**
* Returns a single list of all elements from all collections in the given collection.
*/
public fun <T> Iterable<Iterable<T>>.flatten(): List<T> {
val result = ArrayList<T>()
for (element in this) {
result.addAll(element)
}
return result
}
If you want to save memory, create a Sequence from your list first:
data.asSequence()
and then perform your operations on this sequence:
data.asSequence().flatten().find { n -> n > 4 && n < 6 }
Side note: your predicate, n > 4 && n < 6, is simply equivalent to n == 5.
If you just want to reduce codes and you don't care much about efficiency, try this.
list.flatten().find { your pred here }
Or
list.flatMap { it }.find { your pred }
Or create a useful utility which doesn't create new lists (faster/lower memory taken):
inline fun <T> Iterable<Iterable<T>>.forEachEach(f: (T) -> Unit) =
forEach { it.forEach(f) }

How to achieve a pure function with dynamic programming in Kotlin?

I've been trying to transform some of my code to pure functions to learn how to use Kotlin in a functional way, with this simple snippet of code I can't think of any way to make my calculateFibonacci function a pure function.
I'm aware of a potentially recursive solution but what about a potential stack overflow, does Kotlin implement Tail Call Optimization?
Example:
val fibonacciValues = hashMapOf<Int, BigInteger>(0 to BigInteger.ONE, 1 to BigInteger.ONE);
// * TODO investigate how to do dynamic programming with a pure function ** //
private fun calculateFibonacci(n: Int): BigInteger? {
if (fibonacciValues.contains(n)) {
return fibonacciValues.get(n)
} else {
val f = calculateFibonacci(n - 2)!!.add(calculateFibonacci(n - 1))
fibonacciValues.put(n, f)
return f
}
}
For the whole snippet I uploaded this gist:
https://gist.github.com/moxi/e30f8e693bf044e8b6b80f8c05d4ac12
The whole thing is about breaking out of the imperative approach and thinking in terms of sequence manipulation.
In the case of the Fibonacci Sequence, it might be tricky because it's very tempting to think of it as a sequence of Ints but it gets much easier if you think of it as a sequence of pairs (from which you eventually derive a sequence of Ints)
So, you could create an infinite sequence of pairs where the next pair is defined as the second element of the previous pair and a sum of elements in a previous pair:
generateSequence(1 to 1) { it.second to it.first + it.second }
.map { it.first }
And yes, you can utilize the Tail Call Optimization by marking your method with the tailrec keyword - no worries about the stack overflow. You just apply it before the fun keyword:
fun fibonacciAt(n: Int) = {
tailrec fun fibonacciAcc(n: Int, a: Long, b: Long): Long {
return when (n == 0) {
true -> b
false -> fibonacciAcc(n - 1, a + b, a)
}
}
fibonacciAcc(n, 1, 0)
}
Here is more info about the Tail Recursion in Kotlin.
Homegrown:
fun fib(i: Int): Int {
tailrec fun go(k: Int, p: Int, c: Int): Int {
return if (k == 0) p
else go(k - 1, c, p + c)
}
return go(i, 0, 1)
}
generateSequence actually shows a Fibonacci implementation as example.
fun fibonacci(): Sequence<Int> {
// fibonacci terms
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, ...
return generateSequence(Pair(0, 1), { Pair(it.second, it.first + it.second) }).map { it.first }
}
println(fibonacci().take(10).toList()) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
does Kotlin implements Tail Call Optimization
Yes, there is tailrec keyword for that.

Checking if a returned number is an integer in GP/Pari?

This is my first time using GP/Pari and I am having trouble completing this question.
I am asked to print if the return of the function 'wq()' is an integer. Is there a function that can determine if the number passed in is an integer? If not how would I go about checking? I find the syntax somewhat difficult and can't find much information online about it.
I have included what I have so far, any help is appreciated.
wq(x) =
{
[(x-1)! + 1]/x
}
test(r,s) =
{
for (i=r, s, if(isinteger(wq(i)), print("integer"), print("not interger")));
}
If I understand correctly you want to check if (x-1)! + 1 is a multiple of x. You can do that with the modulo operation:
test(r,s) =
{
for (i=r, s, if(Mod((i - 1)! + 1, i) == 0,
print("integer"),
print("not integer")));
}
You can use:
wq(x) =
{
((x-1)! + 1)/x
}
test(r,s) =
{
for (i=r, s, print(if(type(wq(i))=="t_INT", "integer", "not integer")))
}
I changed [] into () since [] gives a row vector (type t_VEC) which is not useful here.
Here is another way to write it:
wq(x) =
{
Mod((x-1)! + 1, x)
}
test(r,s) =
{
for (i=r, s, wq(i) && print1("not "); print("integer"))
}
The function print1 prints and "stays" on the same line. The 'and' operator && "short-circuits". The semicolon ; binds several expressions into one "sequence".

Finding the even and odd numbers in a linked list by recursion?

Happy new years for everyone! :)
I could do better things in the first day of the year but i'm trying to implement the linked lists and recursion together.
I just thought that how I can achieve to write a function that calculates the even numbers in a linked list with recursion.
void List:: findingEvens(Node* n, Node*& newHead){
if(n == NULL)
return;
else
if(n-> data % 2 != 0)
findingEvens(n-> next);
else{
if(!newHead){
newHead = n;
}
else{
Node* temp =head;
for(;temp->next;temp=temp->next){
temp = temp -> next;
}
temp-> next = n;
findingEvents(n-> next);
}
}
}
The problem is that in my h class I add the following as it should be
void findingEvens(Node* n);
However this makes me error which says that error: ‘Node’ has not been declared
Actually I have a Node struct after the definition of this function in h class.
Is the implementation of the recursive function wrong?
Any help will be appreciated, happy new year again :)
void List:: findingEvens(Node* n, Node*& newHead){
if(n == NULL)
return;
else
if(n-> data % 2 != 0)
findingEvens(n-> next, newHead);
else{
// Push even node onto newHead list
newNode = new Node;
newNode->data = n->data;
newNode->next = newHead;
newHead = newNode;
findingEvens(n-> next, newHead);
}
}
You need to pass newHead in the recursive calls.
You can't just assign n directly to newHead, because then the newHead list will have all the links from the original list. You need to make new nodes and copy the data.
The above code builds the result list in reverse order of the original list, e.g. if you start with 1, 2, 3, 5, 6, 8, 9, the result will be 8, 6, 2. You can reverse the list when it's done.

Resources