Intersection of several lists with reduce - kotlin

I wanted to create a function that returns an intersection of several lists. I did something like this:
fun <T> List<List<T>>.intersection(): List<T> {
return this.reduce { acc, it -> acc.apply { acc.toMutableSet().retainAll(it.toSet()) } }
}
I called it with List<List<Int>> like this [[12, 321], [4, 35, 4], [67, 57, 8], [98, 97]], but it keeps returning me the first list. The expected list should be an empty list.
I added an also to see what this reduce is called with and it is the same (the first one) list all the time.
Can someone explain what I'm doing wrong here and how can I write that function with reduce?

Your code currently creates a copy of acc as a mutable set, removes the elements not in it, and then does nothing with it. You never actually save or return the results. acc.apply only reflects modifications actually made to acc, not anything you did with copies of acc.

Related

How to call 2 fluxes in parallel and manipulate on them afterwards

So I'm new to reactive programming and writing my first program using spring web-flux and I want to call 2 resources in parallel but I couldn't find how.
I've already Implemented the following methods
public Flux<Date> getDatesToExclude(); //fetches dates from external api
public Flux<UserDates> getAvailableUserDates(); //fetches dates from a json file
UserDates DTO
public class UserDates{
private String user;
private List<Date> dates;
//* getters setters *//
}
and I want to implement the following which should
request getDatesToExclude() and getAvailableUserDates() in parallel.
filter getAvailableUserDates() to the specific user.
filter out the dates to exclude.
public Flux<UserDates> getAvailableUserDates(String user);
I tried to chain the methods using zipWith but found it would work on the items 1 by 1 which doesn't seem useful in this case.
Do I have to use completableFuture in this case?
Just use collectList() and also make sure your different flux executions will be executed on different threads. Below is an example that you can easily adapt to your code.
Mono<List<String>> words = Flux.just("sun", "sky", "beach", "water", "sun", "tree")
.delayElements(Duration.ofMillis(100)) // just to slow down emitting, for testing
.filter(user -> user.equals("sun")) // we want to filter only "sun" words
.collectList() // collect all the filtered items to a List
.subscribeOn(Schedulers.parallel()); // when subscription is made, the process with start on parallel scheduler
Mono<List<Integer>> values = Flux.just(1, 2, 6, 1, 20, 31, 4, 1, 3, 21, 44, 67, 1, 90, 87)
.delayElements(Duration.ofMillis(200)) // just to slow down emitting, for testing
.filter(value -> value.equals(1)) // we want to filter only values equal to 1
.collectList() // collect all the filtered items to a List
.subscribeOn(Schedulers.parallel()); // when subscription is made, the process with start on parallel scheduler
Mono.zip(words, values)
.doOnNext(tuple -> {
// do whatever you want with
// tuple.getT1() - list of words results
// tuple.getT2() - list of values results
// I use doOnNext() just for print something, but you should use the operator that depends on your purposes
System.out.println(String.format("Words list size: %s, values list size: %s",
tuple.getT1().size(), tuple.getT2().size())
);
})
.subscribe();
Thread.sleep(10000L);
// just for testing purposes since all the processes after subscribe()
// happen on other threads

How do I make this Sequence lazy?

I was trying to generate all permutations of a list in Kotlin. There are a zillion examples out there which return a List<List<T>>, but my input list breaks those as they try to fit all the results in the output list. So I thought I would try to make a version returning Sequence<List<T>>...
fun <T> List<T>.allPermutations(): Sequence<List<T>> {
println("Permutations of $this")
if (isEmpty()) return emptySequence()
val list = this
return indices
.asSequence()
.flatMap { i ->
val elem = list[i]
(list - elem).allPermutations().map { perm -> perm + elem }
}
}
// Then try to print the first permutation
println((0..15).toList().allPermutations().first())
Problem is, Kotlin just seems to give up and asks for the complete contents of one of the nested sequences - so it never (or at least not for a very long time) ends up getting to the first element. (It will probably run out of memory before it gets there.)
I tried the same using Flow<T>, with the same outcome.
As far as I can tell, at no point does my code ask it to convert the sequence into a list, but it seems like something internal is doing it to me anyway, so how do I stop that?
As mentioned in the comments, you have handled the empty base case incorrectly. You should return a sequence of one empty list.
// an empty list has a single permutation - "itself"
if (isEmpty()) return sequenceOf(emptyList())
If you return an empty sequence, first will never find anything - your sequence is always empty - so it will keep evaluating the sequence until it ends, and throw an exception. (Try this with a smaller input like 0..2!)

The least amount of letters in a list of Palindromes

So the question is giving a BIG string, break it up, find the palindromes and then find the shortest length within those sets of palindromes. Here's the code
Main Function
fun main(){
val bigArray = "Simple, given a string of words, return the length of acdca the " +
"shortest valav words String will never be empty and you do not need dad to account for different data types."
println(leastP(bigArray))
}
The Custom Function
fun leastP(s: String): Int {
val sSplit = listOf(s.split(""))
val newArray = listOf<String>()
for (i in sSplit){
for (j in i.indices){
if (isPalindrome3(i[j])) newArray.plus(j)
}
}
return newArray.minOf { it.length }
}
private fun isPalindrome3(s: String): Boolean {
var i = 0
var j = s.length -1
while (i < j){
if (s[i++].lowercaseChar() != s[j--].lowercaseChar()) return false
}
return true
}
}
I get this error
Not sure whats going on or where I messed up. Any help is appreciated.
In addition to the array problem identified in Tenfour04's answer, the code has an additional problem:
split("") splits the string into individual characters, not just individual words. 
If you debug it, you'll find that isPalindrome3() is being called first on an empty string, then on "S", then on "i", and so on.
That's because the empty string "" matches at every point in the input.
The easiest fix is to call split(" "), which will split it at space characters.
However, that might not do exactly what you want, for several reasons: it will include empty strings if the input has runs of multiple spaces; it won't split at other white space characters such as tabs, newlines, non-breaking spaces, en spaces, etc.; and it will include punctuation such as commas and full stops. Splitting to give only words is harder, but you might try something like split(Regex("\\W") to include only letters, digits, and/or underscores. (You'll probably want something more sophisticated to include hyphens and apostrophes, and ensure that accented letters etc. are included.)
There's a further issue that may or may not be a problem: you don't specify a minimum length for your palindromes, and so words like a match. (As do empty strings, if the split produces any.) If you don't want the result to be 0 or 1, then you'll also have to exclude those.
Also, the code is currently case-sensitive: it would not count "Abba" as a palindrome, because the first A is in upper case but the last a isn't. If you wanted to check case-insensitively, you'd have to handle that.
As mentioned in a comment, this is the sort of thing that should be easy to test and debug. Short, self-contained functions with no external dependencies are pretty easy to write unit tests for. For example:
#Test fun testIsPalindrome3() {
// These should all count as palindromes:
for (s in listOf("abcba", "abba", "a", "", "DDDDDD"))
assertTrue(isPalindrome3(s))
// But these shouldn't:
for (s in listOf("abcbb", "Abba", "a,", "abcdba"))
assertFalse(isPalindrome3(s))
}
A test like that should give you a lot of confidence that the code actually works. (Especially because I've tried to include corner cases that would spot all the ways it could fail.) And it's worth keeping unit tests around once written, as they can verify that the code doesn't get broken by future changes.
And if the test shows that the code doesn't work, then you have to debug it! There are many approaches, but I've found printing out intermediate values (whether using a logging framework or simply println() calls) to be the simplest and most flexible.
And for reference, all this can be rewritten much more simply:
fun String.leastP() = split(Regex("\\W"))
.filter{ it.length >= 2 && it.isPalindrome() }
.minOfOrNull{ it.length }
private fun String.isPalindrome() = this == reversed()
Here both functions are extension functions on String, which makes them a bit simpler to write and to call. I've added a restriction to 2+ characters. And if the input is empty, minOfOrNull() returns null instead of throwing a NoSuchElementException.
That version of isPalindrome() isn't quite as efficient as yours, because it creates a new temporary String each time it's called. In most programs, the greater simplicity will win out, but it's worth bearing in mind. Here's one that's longer but as efficient as in the question:
private fun String.isPalindrome()
= (0 until length / 2).all{ i -> this[i] == this[length - i - 1]}
Your newArray is a read-only list. When you call plus on it, the function does not modify the original list (after all, it is read-only). The List.plus() function returns a new list, which you are promptly discarding by not assigning it to any variable or property.
Then it crashes because it is unsafe to call minOf on an empty list.
Two different ways to fix this:
Make the newArray variable a var and replace newArray.plus(j) with newArray += j. The += operator, when used on a read-only list that is assigned to a mutable var variable, calls plus() on it and assigns the result back to the variable.
Initialize newArray as a MutableList using mutableListOf() and replace newArray.plus(j) with newArray += j. The += operator, when used with a MutableList, calls add() or addAll() on the MutableList, so it directly changes the original instance.
I didn’t check any of your logic. I’m only answering the question about why it’s crashing.
But as Gidds points out, the logic can be simplified a ton to achieve the same thing you’re trying to do using functions like filter(). A few odd things you’re doing:
Putting the result ofstring.split("") in a list for no reason
Using "" to split your string so it’s just a list of one-character Strings instead of a list of words. And you’re ignoring punctuation.
Filling newArray with indices so minOf will simply give you the first index that corresponded with being a palindrome, so it will always be 0.
Here’s how I might write this function (didn’t test it):
fun leastP(s: String): Int {
return s.split(" ")
.map { it.filter { c -> c.isLetter() } }
.filter { isPalindrome3(it) }
.minOfOrNull { it.length } ?: 0
}

Grouping and ordering the top 3 values in a list

I have a list similar in concept to the following:
val selectedValues = listOf("Apple", "Apple", "Apple", "Grape", "Grape", "Cherry")
I need a way to group and sort it so that I get something like this:
Apple: 3
Grape: 2
Cherry: 1
I got a little bit of headway with this answer but I want it to be ordered by the count (most to least) and I can't seem to figure out how to get there.
I feel like the answer I posted gets me very close to what I want but I just need to figure out how to get it to work the way I need to and I'm just hitting a wall and need a little assistance as I'm still fairly new to Kotlin.
You could try something like this:
fun main(args : Array<String>) {
val selectedValues = listOf("Apple", "Apple", "Apple", "Grape", "Grape", "Cherry")
val solution = selectedValues
.groupBy { it }
.mapValues { it.value.size }
.toList()
.sortedByDescending { (_, value) -> value }
.toMap()
println(solution)
}
This will returns you
{Apple=3, Grape=2, Cherry=1}
which I think is (more or less) what you were after.
If you want to get a bit clever, you can use a Grouping which allows you to do a group-and-fold operation, i.e. group a bunch of things and then turn each group into a result - there's an eachCount() operation which turns each group into a count:
selectedValues.groupingBy { it }.eachCount()
.entries
.sortedByDescending { it.value }
.take(3) // they're still Entry pairs here, so you can toMap() if you need one
.run(::println)
Stefano's approach is the most general (and definitely what I'd go for if you're still starting out), but there are some specific tools for some scenarios too (possibly with some performance optimisation going on under the hood)
There's also the "build your own map of counts" approach:
// this is basically the same as "val newMap, stuff.forEach { update count in newMap }"
selectedValues.fold(mutableMapOf<String, Int>()) { counts, item ->
counts.apply { put(item, getOrDefault(item, 0) + 1) }
}
which I think is how the groupingBy().eachCount() combo above works - instead of creating a map of lists ("Apple"=["Apple", "Apple", "Apple"] and so on) and then generating a map of Ints from that, you just generate the Map<String, Int> from the original source list.
Whatever's easiest honestly, you only need to worry about efficiency when you're dealing with a lot of stuff, and Kotlin lets you write nice readable operations with its basic functions. Just thought I'd give you an idea of some of the options you have since you were struggling a little, in case it helps some things click!

passing lambda to joinToString in kotlin?

I am new to Kotlin and I am struggling to understand following code:
println((1..5).joinToString(", ") { (it * 2).toString() }) // 2, 4, 6, 8, 10
From my understanding the above code should have been written like this:
println((1..5).map { it * 2 }.joinToString(", ")) // 2, 4, 6, 10
To which function are we passing the lambda { (it * 2).toString() } and why do we have .toString() there? I didn't find any clue in documentation of joinToString either. So, how does this work?
joinToString has an optional parameter called transform of type ((T) -> CharSequence)?. If a non-null argument is passed for that parameter, joinToString will run it on each element of the receiver collection before joining the elements into a string. Let's look at both code snippets you've provided in more detail:
println((1..5).joinToString(", ") { (it * 2).toString() })
Here, you're calling joinToString on a range of (1..5). You're passing a transform function, { (it * 2).toString() }, so before joining the elements of the range into a string, joinToString will multiply each of them by 2. You'll also need to call toString() on the result of the multiplication since the signature of transform is (T) -> CharSequence.
A piece of general advice: whenever you're confused by Kotlin's terse syntax, reduce the level of terseness until you fully understand the code. In this case, changing the snippet to the following might make it easier to understand:
println((1..5).joinToString(", ", transform = { (it * 2).toString() }))
The second snippet produces the exact same result:
println((1..5).map { it * 2 }.joinToString(", "))
You don't need the transform function here since the elements are already multiplied by 2 inside map.
A note on performance (this is irrelevant here cause the size of the input is too small, but important for large inputs), map will have to copy the entire collection, hence the second variant will be slower and less memory efficient. The first variant does not have that problem.