How does compareBy work in kotlin using a boolean expression - sorting

I know from official documentation that compareBy
creates a comparator using the sequence of functions to calculate a result of comparison. The functions are called sequentially, receive the given values a and b and return Comparable objects.
I know how this must be done for normal attributes like the integer value here, but how are boolean conditions handled by compareBy?
In this example, I intended to keep all 4's at the top of the list and then sort in ascending order of values, but I am not sure how this boolean expression helps me do this!
fun main(args: Array<String>) {
var foo = listOf(2, 3, 4, 1, 1, 5, 23523, 4, 234, 2, 2334, 2)
foo = foo.sortedWith(compareBy({
it != 4
},{
it
}))
print(foo)
}
Output
[4, 4, 1, 1, 2, 2, 2, 3, 5, 234, 2334, 23523]

Boolean is Comparable
public class Boolean private constructor() : Comparable<Boolean>
So when you're returning it != 4 in compareBy you're using Boolean's sort order i.e. false < true. Your expression is false only when it == 4, and indeed you can see the 4s as the first elements in the output.

Your code provides two selectors as a vararg to compareBy :
foo.sortedWith(
compareBy(
{ it != 4 },
{ it }
)
)
Digging into the sources we have a Comparator for any two values a and b built up: Comparator { a, b -> compareValuesByImpl(a, b, selectors) }
and finally:
private fun <T> compareValuesByImpl(a: T, b: T, selectors: Array<out (T) -> Comparable<*>?>): Int {
for (fn in selectors) {
val v1 = fn(a)
val v2 = fn(b)
val diff = compareValues(v1, v2)
if (diff != 0) return diff
}
return 0
}
The last code snippet demonstrates that if all selectors have the same diff, a and b are considered equal otherwise the first selector with diff != 0 wins.
Booleans are comparable. When comparing 4 with any other value, say 2, you will have:
4 != 4 false
2 != 4 true
diff = false.compareTo( true ) == -1
and so, for sorting, 4 is "less" then any value that is not 4

Related

counting pairs in a list

I've recently started on HackerRank and I'm attempting "Sales by Match". I've arrived at a solution I'm content with in terms of exploiting Kotlin's function programming capabilities. However, I'm not getting the expected answer...
Problem summary:
Given an Array:
-> find and return the total number of pairs.
i.e:
input -> [10, 20, 20, 10, 10, 30, 50, 10, 20]
number of pairs -> 3
here is my code and some comments to explain it:
fun sockMerchant(n: Int, pile: Array<Int>): Int{
var count = 0
mutableMapOf<Int, Int>().withDefault { 0 }.apply {
// the [attempted] logic behind this piece of code here is
// that as we iterate through the list, the 'getOrPut()'
// function will return either the value for the given [key]
// or throw an exception if there is no such key
// in the map. However, since our map was created by
// [withDefault], the function resorts to its `defaultValue` <-> 0
// instead of throwing an exception.
for (e in values) {
// this simplifies our code and inserts a zero [+1] where needed.
// if (key exists)
// // return its associated value and MOD it:
// case: even -> increment counter
// else -> do nothing
// else if (key dne)
// // insert default value <-> [0] + 1
// ....
// ....
// ....
if (getOrPut(e, { getValue(e) + 1 } ) % 2 == 0) count++
}
}
return count
}
fun main(args: Array<String>) {
val scan = Scanner(System.`in`)
val n = scan.nextLine().trim().toInt()
val ar = scan.nextLine().split(" ").map{ it.trim().toInt() }.toTypedArray()
val result = sockMerchant(n, ar)
println(result)
}
--
Any help or tips would go a long way here:)
I was able to do this by grouping the numbers together, taking the resulting lists, and summing how many pairs each one contains:
fun sockMerchant(n: Int, pile: Array<Int>): Int =
pile.groupBy { it }.values.sumBy { it.size / 2 }
After we do pile.groupBy { it }, we have this structure:
{10=[10, 10, 10, 10], 20=[20, 20, 20], 30=[30], 50=[50]}
We take the values, and sum by each of their size dividing by 2. This will round half-pairs down to 0 and full pairs to 1 each.
Note: I am not entirely clear what the purpose of n is in this case.
I modified it a bit to be more easily testable, but here is the fixes :
import java.util.*
fun sockMerchant(n: Int, pile: Array<Int>): Int{
var count = 0
mutableMapOf<Int, Int>().withDefault { 0 }.apply {
// the [attempted] logic behind this piece of code here is
// that as we iterate through the list, the 'getOrPut()'
// function will return either the value for the given [key]
// or throw an exception if there is no such key
// in the map. However, since our map was created by
// [withDefault], the function resorts to its `defaultValue` <-> 0
// instead of throwing an exception.
for (e in pile) {
// this simplifies our code and inserts a zero [+1] where needed.
// if (key exists)
// // return its associated value and MOD it:
// case: even -> increment counter
// else -> do nothing
// else if (key dne)
// // insert default value <-> [0] + 1
// ....
// ....
// ....
println(e)
put(e, getValue(e) + 1)
if (getValue(e) % 2 == 0) count++
println(entries)
}
}
return count
}
val n = 5
val ar = "10 10 10 10 20 20 30 40".split(" ").map{ it.trim().toInt() }.toTypedArray()
val result = sockMerchant(n, ar)
println(result)
Output :
10
[10=1]
10
[10=2]
10
[10=3]
10
[10=4]
20
[10=4, 20=1]
20
[10=4, 20=2]
30
[10=4, 20=2, 30=1]
40
[10=4, 20=2, 30=1, 40=1]
3
Pair.kts:3:18: warning: parameter 'n' is never used
fun sockMerchant(n: Int, pile: Array<Int>): Int{
^
Process finished with exit code 0
Explanation :
You looped over "values", which is at start empty, so you never did anything with your code
Even when looping over pile, your incrementation logic didn't go above 1, so the condition was never satisfied and the count was never incremented.
But the main reasoning behind was correct.

Optimizing the algorithm to run under 4 seconds for a quite large number of operations

I have the following code which is for solving the practise challanges from hackerrank.
And there are literally 10^7 values to be created in a list and then each should be incremented according to 10^5 queries (with console read time included), I need to crack it within 4 seconds. Here is total inputs (with queries).
First line contains two numbers, first(n) is the number of values in list, second(m) is the number of queries following below. All lines below are queries have 3 numbers, first(a) and second(b) is the indexes (starting from 1), third(k) is the value to be added into the list within the indexes. And then finally the maximum in the list should be console ouput.
private fun readLn() = readLine()!! // string line
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints
fun main() {
val (n, m) = readInts()
val list = MutableList(n) { 0L }
repeat(m) {
val queries = readStrings()
val a = queries[0].toInt() - 1
val b = queries[1].toInt() - 1
val k = queries[2].toLong()
for (i in a..b) {
list[i] += k
}
}
println(list.max())
}
Currently it seems well optimized for me, but still can't do all the operations within 4 seconds.
Any help would be appreciated, Thanks in advance!
Edit - After answer provided by #Photon, I've modified the code but still with that algorithm as well the time limit is reached for same test cases.
Here is the modified code -
private fun readLn() = readLine()!! // string line
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints
fun main() {
val (n, m) = readInts()
val list = MutableList(n + 2) { 0L }
repeat(m) {
val queries = readStrings()
val a = queries[0].toInt()
val b = queries[1].toInt()
val k = queries[2].toLong()
list[a] += k
list[b + 1] -= k
}
for (i in 1..n + 1) {
list[i] = list[i - 1] + list[i]
}
println(list.max())
}
Brute force is simply too slow no matter how much you optimize this. Here`s a simple array trick to solve this in O(N + Q) time:
First we have array of zeroes of size N+2: A = [0, 0, 0, 0, ..., 0]
For query L R K instead of increasing all numbers in interval we can increase first one by K and R+1 one by -K
then after all queries we can modify array by adding A[i-1] for all i in [1, N]
this will be the same as doing all queries
It might be confusing so here's an example:
N=5 so our initial array: A = [0, 0, 0, 0, 0, 0, 0]
lets say we have a query: 1 3 3
updated array: A = [0, 3, 0, 0, -3, 0, 0]
lets say we have another query: 2 5 10
updated array: A = [0, 3, 10, 0, -3, 0, -10]
now after all queries we can add A[i-1] for all i in [1, 5]
updated array: A = [0, 3, 13, 13, 10, 10, 0]
notice is`s the same as doing all queries by brute force

How to filter a flux for all elements having the highest value

How do I filter a publisher for the elements having the highest value without knowing the highest value beforehand?
Here is a little test to illustrate what I'm trying to achieve:
#Test
fun filterForHighestValuesTest() {
val numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3)
// what operators to apply to numbers to make the test pass?
StepVerifier.create(numbers)
.expectNext(8)
.expectNext(8)
.verifyComplete()
}
Ive started with the reduce operator:
#Test
fun filterForHighestValuesTestWithReduce() {
val numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3)
.reduce { a: Int, b: Int -> if( a > b) a else b }
StepVerifier.create(numbers)
.expectNext(8)
.verifyComplete()
}
and of course that test passes but that will only emit a single Mono whereas I would like to obtain a Flux containing all the elements having the highest values e.g. 8 and 8 in this simple example.
First of all, you'll need state for this so you need to be careful to have per-Subscription state. One way of ensuring that while combining operators is to use compose.
Proposed solution
Flux<Integer> allMatchingHighest = numbers.compose(f -> {
AtomicInteger highestSoFarState = new AtomicInteger(Integer.MIN_VALUE);
AtomicInteger windowState = new AtomicInteger(Integer.MIN_VALUE);
return f.filter(v -> {
int highestSoFar = highestSoFarState.get();
if (v > highestSoFar) {
highestSoFarState.set(v);
return true;
}
if (v == highestSoFar) {
return true;
}
return false;
})
.bufferUntil(i -> i != windowState.getAndSet(i), true)
.log()
.takeLast(1)
.flatMapIterable(Function.identity());
});
Note the whole compose lamdba can be extracted into a method, making the code use a method reference and be more readable.
Explaination
The solution is done in 4 steps, with the two first each having their own AtomicInteger state:
Incrementally find the new "highest" element (so far) and filter out elements that are smaller. This results in a Flux<Integer> of (monotically) increasing numbers, like 1 5 7 8 8.
buffer by chunks of equal number. We use bufferUntil instead of window* or groupBy because the most degenerative case were numbers are all different and already sorted would fail with these
skip all buffers but one (takeLast(1))
"replay" that last buffer, which represents the number of occurrences of our highest value (flatMapIterable)
This correctly pass your StepVerifier test by emitting 8 8. Note the intermediate buffers emitted are:
onNext([1])
onNext([5])
onNext([7, 7, 7])
onNext([8, 8])
More advanced testing, justifying bufferUntil
A far more complex source that would fail with groupBy but not this solution:
Random rng = new Random();
//generate 258 numbers, each randomly repeated 1 to 10 times
//also, shuffle the whole thing
Flux<Integer> numbers = Flux
.range(1, 258)
.flatMap(i -> Mono.just(i).repeat(rng.nextInt(10)))
.collectList()
.map(l -> {
Collections.shuffle(l);
System.out.println(l);
return l;
})
.flatMapIterable(Function.identity())
.hide();
This is one example of what sequence of buffers it could filter into (keep in mind only the last one gets replayed):
onNext([192])
onNext([245])
onNext([250])
onNext([256, 256])
onNext([257])
onNext([258, 258, 258, 258, 258, 258, 258, 258, 258])
onComplete()
Note: If you remove the map that shuffles, then you obtain the "degenerative case" where even windowUntil wouldn't work (the takeLast would result in too many open yet unconsumed windows).
This was a fun one to come up with!
One way to do it is to map the flux of ints to a flux of lists with one int in each, reduce the result, and end with flatMapMany, i.e.
final Flux<Integer> numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3);
final Flux<Integer> maxValues =
numbers
.map(
n -> {
List<Integer> list = new ArrayList<>();
list.add(n);
return list;
})
.reduce(
(l1, l2) -> {
if (l1.get(0).compareTo(l2.get(0)) > 0) {
return l1;
} else if (l1.get(0).equals(l2.get(0))) {
l1.addAll(l2);
return l1;
} else {
return l2;
}
})
.flatMapMany(Flux::fromIterable);
One simple solution that worked for me -
Flux<Integer> flux =
Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3).collectSortedList(Comparator.reverseOrder()).flatMapMany(Flux::fromIterable);
StepVerifier.create(flux).expectNext(8).expectNext(8).expectNext(7).expectNext(5);
One possible solution is to group the Flux prior to the reduction and flatmap the GroupedFlux afterwards like this:
#Test
fun filterForHighestValuesTest() {
val numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3)
.groupBy { it }
.reduce { t: GroupedFlux<Int, Int>, u: GroupedFlux<Int, Int> ->
if (t.key()!! > u.key()!!) t else u
}
.flatMapMany {
it
}
StepVerifier.create(numbers)
.expectNext(8)
.expectNext(8)
.verifyComplete()
}

Single Number 2 Scala solution

Given an array of integers, every element appears three times except for one, which appears exactly once. Find that single one. This is what I have now. But I don't know how to break the for loop once I get the single number "b". Any solution in scala please?
for(Array(a,b) <- nums.sorted.sliding(2))
{
if (a == b){j = j+1}
else
{
if (j < 3) j =1
b
}
}
This will do it.
nums.groupBy(identity).find(_._2.length == 1).get._1
It's a bit unsafe in that it will throw if there is no single-count element. It can be made safer if a default value is returned when no single-count element is found.
nums.groupBy(identity).find(_._2.length == 1).fold(-1)(_._1)
Another way is to sum the array by adding digits of two numbers in base 3 modulo 3 (in other words XOR in base 3). The elements that appear 3 times will become zero, so the result of this sum will be the single number.
def findSingleNumber(numbers: Array[Int]) = {
def add3(a: String, b: String): String = a.zipAll(b, '0', '0').map {
case (i, j) => ((i.toInt + j.toInt) % 3 + '0').toChar
}(collection.breakOut)
val numbersInBase3 = numbers.map(n => Integer.toString(n, 3).reverse)
Integer.parseInt(numbersInBase3.fold("0")(add3).reverse, 3)
}
scala> findSingleNumber(Array(10, 20, 30, 100, 20, 100, 10, 10, 20, 100))
res1: Int = 30
Or representing base 3 numbers as digit arrays:
def findSingleNumber(numbers: Array[Int]) = {
def toBase3(int: Int): Array[Int] =
Iterator.iterate(int)(_ / 3).takeWhile(_ != 0).map(_ % 3).toArray
def toBase10(arr: Array[Int]): Int =
arr.reverseIterator.foldLeft(0)(_ * 3 + _)
def add3(a: Array[Int], b: Array[Int]): Array[Int] = a.zipAll(b, 0, 0).map {
case (i, j) => (i + j) % 3
}
toBase10(numbers.map(toBase3).fold(Array.empty[Int])(add3))
}

Scala code bubble sort for loop

object BubbleSort {
def main(args : Array[String]) : Unit = {
bubbleSort(Array(50,33,62,21,100)) foreach println
}
def bubbleSort(a:Array[Int]):Array[Int]={
for(i<- 1 to a.length-1){
for(j <- (i-1) to 0 by -1){
if(a(j)>a(j+1)){
val temp=a(j+1)
a(j+1)=a(j)
a(j)=temp
}
}
}
a
}
}
I have the above code supposedly implementing bubble sort in Scala. It is sorting the given numbers in the main but is it a well implemented Bubble Sorting algorithm?
Also what does this line of code mean in pseudocode: for(j <- (i-1) to 0 by -1){
I can't understand it.
Thanks for your help
The best way to figure out what a bit of Scala code does is to run it in the REPL:
scala> 5 to 0 by -1
res0: scala.collection.immutable.Range = Range(5, 4, 3, 2, 1, 0)
So that code counts from (i-1) to 0, backwards.
More generally, x to y creates a Range from integer x to integer y. The by portion modifies this counting. For example, 0 to 6 by 2 means "count from 0 to 6 by 2", or Range(0, 2, 4, 6). In our case, by -1 indicates that we should count backwards by 1.
As for understanding how bubble sort works, you should read the Wikipedia article and use that to help you understand what the code is doing.
This can be the shortest functional implementation of Bubble sort
/**
* Functional implementation of bubble sort
* sort function swaps each element in the given list and create new list and iterate the same operation for length of the list times.
* sort function takes three parameters
* a) iteration list -> this is used to track the iteration. after each iteration element is dropped so that sort function exists the iteration list is empty
* b) source list -> this is source list taken for element wise sorting
* c) result -> stores the element as it get sorted and at end of each iteration, it will be the source for next sort iteration
*/
object Test extends App {
def bubblesort(source: List[Int]) : List[Int] = {
#tailrec
def sort(iteration: List[Int], source: List[Int] , result: List[Int]) : List[Int]= source match {
case h1 :: h2 :: rest => if(h1 > h2) sort(iteration, h1 :: rest, result :+ h2) else sort(iteration, h2 :: rest, result :+ h1)
case l:: Nil => sort(iteration, Nil, result :+ l)
case Nil => if(iteration.isEmpty) return result else sort(iteration.dropRight(1), result, Nil )
}
sort(source,source,Nil)
}
println(bubblesort(List(4,3,2,224,15,17,9,4,225,1,7)))
//List(1, 2, 3, 4, 4, 7, 9, 15, 17, 224, 225)
}
The example you have posted is basically a imperative or Java way of doing bubble sort in Scala which is not bad but defies the purpose of Functional Programming in Scala.. the same code can we written sorter like below (basically combining both the for loops in one line and doing a range on the source length)
def imperativeBubbleSort[T <% Ordered[T]](source: Array[T]): Array[T] = {
for (i <- 0 until source.length - 1; j <- 0 until source.length - 1 - i) {
if (source(j) > source(j + 1)) {
val temp = source(j)
source(j) = source(j + 1)
source(j + 1) = temp
}
}
source
}
Scala Flavor of bubble sort can be different and simple example is below
(basically usage of Pattern matching..)
def bubbleSort[T <% Ordered[T]](inputList: List[T]): List[T] = {
def sort(source: List[T], result: List[T]) = {
if (source.isEmpty) result
else bubble(source, Nil, result)
}
def bubble(source: List[T], tempList: List[T], result: List[T]): List[T] = source match {
case h1 :: h2 :: t =>
if (h1 > h2) bubble(h1 :: t, h2 :: tempList, result)
else bubble(h2 :: t, h1 :: tempList, result)
case h1 :: t => sort(tempList, h1 :: result)
}
sort(inputList, Nil)
}
#tailrec
def bubbleSort(payload: List[Int], newPayload: List[Int], result: List[Int]): List[Int] = {
payload match {
case Nil => result
case s::Nil => bubbleSort(newPayload, List.empty, s::result)
case x::xs => x.compareTo(xs.head) match {
case 0 => bubbleSort(xs, x::newPayload, result)
case 1 => bubbleSort(x::xs.tail, xs.head::newPayload, result)
case -1 => bubbleSort(xs, x::newPayload, result)
}
}
}
val payload = List(7, 2, 5, 10, 4, 9, 12)
bubbleSort(payload, List.empty, List.empty)

Resources