How merge two list of objects and identify identical elements - kotlin

I have 2 lists containing objects of the same type and I am looking to merge these 2 lists.
Let's take an example:
List1 contains [A, B, C, E]
List2 contains [A, D]
what I need [A, B, C, E, D]
I absolutely want the identical elements (here the object A) to be those of my list 1.
It does not matter if the order of the items is not kept.

If you want to keep identical elements from list1, you should not use distinct. Your code should be explicit on this business rule to avoid future errors.
An example :
class Elt(private val id: Int, private val content: String) {
open fun equals(other: Elt): Boolean {
return this.id == other.id
}
override fun toString(): String {
return "$id -> $content"
}
}
fun main(args: Array<String>) {
val l1 = listOf(Elt(1,"L1"), Elt(2,"L1"), Elt(3,"L1"), Elt(4,"L1"))
val l2 = listOf(Elt(1,"L2"), Elt(5,"L2"))
val l4 = l2 + l1
println(l4.distinct()) // Elt 1 comes from L2
val l5 = l1 + l2
println(l5.distinct()) // Elt 1 comes from L1
val l6 = l2.toMutableList().apply { addAll(l1) }.distinct()
println(l6.distinct()) // Elt 1 comes from L2
}
It will print:
[1 -> L1, 2 -> L1, 3 -> L1, 4 -> L1, 1 -> L2, 5 -> L2]
[1 -> L2, 5 -> L2, 1 -> L1, 2 -> L1, 3 -> L1, 4 -> L1]
[1 -> L1, 2 -> L1, 3 -> L1, 4 -> L1, 1 -> L2, 5 -> L2]
[1 -> L2, 5 -> L2, 1 -> L1, 2 -> L1, 3 -> L1, 4 -> L1]
If you remove duplicate in list2 before adding the elements, you will ensure that you keep identical ielement from list1:
val l3 = l1 + (l2 - l1.intersect(l2))
println(l3)

Simple case:
val lista = listOf( 1,2,3 )
val listb = mutableListOf( 1,4,5 ).apply { addAll(lista) }.distinct()
// result listb -> [1, 4, 5, 2, 3]

To add two string list
val a = listOf("a","b" ,"c" , "e")
val b = listOf("a", "d")
val c = a + b
To have only distinct values,
val d = c.distinct()

An alternative to the above solutions: use HashSet. Set collections don't support multiple occurrences of the same element so when you add A twice, the second one simply gets discarded.
var s: HashSet<String> = HashSet<String>()
s.addAll(listOf("A", "B", "C", "E"))
s.addAll(listOf("A", "D"))
var l = s.toList()
Since HashSet uses hashing under the hood, you get O(1) complexity on most of its operations.

Related

Two sum in kotlin

Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
I am adding piece of code.
fun main() {
// val nums = intArrayOf(2, 7, 11, 15)
// val target = 9
val nums = intArrayOf(3, 2, 4)
val target = 6
// val nums = intArrayOf(3, 3)
// val target = 6
twoSum(nums, target).forEach {
print(" $it")
}
}
fun twoSum(nums: IntArray, target: Int): IntArray {
val map = mutableMapOf<Int, Int>()
nums.forEachIndexed { index, i ->
map[i]?.let {
return intArrayOf(it, index)
}
map[target - i] = index
}
return intArrayOf()
}
My youtube link is described that I am debugging the code. My question is how
map[i]?.let {
return intArrayOf(it, index)
}
is going inside the 1st and 2nd iteration of return statment and it not going in 3rd iteration. Can anyone help me on this. Thanks

How use arrow-kt to convert a function taking two parameters into a function taking a pair?

I wrote this goofy tuplize function:
fun foo(x: Int, y: Int) = 3 * x + 2 * y + 1
fun <T, U, R> tuplize(f: (T, U) -> R): ((Pair<T, U>) -> R) = { (a, b): Pair<T, U> -> f(a, b) }
val xs = listOf(Pair(1, 2), Pair(42, 23))
val f = tuplize(::foo)
val ys = xs.map(f)
It works, but I guess arrow-kt already has something nice build-in, and I just can't find it. Can you help me out? :)
(Sure, I could just use val ys = xs.map { (a, b) -> foo(a, b) }, but in this example, the goal is to express it in point-free style.)

Morphism where the algebra receives the item's position

Which one is the appropriate morphism (recursion scheme) to use when the given item's position (index, or path) is required in the transformer function?
A simple example would be transforming a list ["foo", "bar", "qux"] into the string "foo, bar, and qux". The current element's position is needed to know when to insert the and.
You need to make the index part of the structure so it is available to the recursion scheme. An ad-hoc way to do this is to define a foldWithIndex function:
foldWithIndex :: (Foldable t, Num i) => (i -> a -> b -> b) -> b -> t a -> b
foldWithIndex f z t = snd $ foldr f' (0, z) t
where
f' z (i, x) = (i + 1, f i z x)
This function takes an operator for combining the elements which also considers the index:
foldWithIndex combine "" ["foo", "bar", "qux"]
where
combine 0 s1 s2 = s1 ++ s2
combine 1 s1 s2 = s1 ++ " and " ++ s2
combine _ s1 s2 = s1 ++ ", " ++ s2
results in "foo, bar and qux".
For a more general approach see Data.Foldable.WithIndex, which provides a foldable typeclass that also takes an index into account.

Find the first element in a list that verify a condition

Assuming we are given a list of integers R = [3,5,3,6,0,6,7], an threshold x (integer) and a window size (integer) p. For example, x=4 and p = 2.
I need to find the first index t that verifies the the following conditions:
R[t] >= 4, R[t+1] >= 4. Since p=2, we need to only verify for two boxes t and t+1. If p was equal to 3 we will need to verify for t, t+1 and t+2.
Here the t I am looking for is 5 (indexing is starting from 0).
How to write this in a elegant way in Kotlin (rather than looping on the elements).
A tentative that is giving an error (x=4 and p = 2. The output should be 3 since we start indexing by 0):
val numbers = listOf(1, 2, 3, 4, 6, 8, 2)
val firstIndex = numbers.find { it >= 4 for it in it..it+2-1}
val numbers = listOf(1, 2, 3, 4, 6, 8, 2)
val p = 2
val x = 4
val t = numbers.windowed(p).indexOfFirst { window -> window.all { it >= x } } // t == 3
t will be equal to -1 in case if no matches will be found
Use windowed to check groups of values for each index in the list. Use withIndex() so you are iterating with the indices, which you need in your final result. Then use firstOrNull() (which find() is a redundant alias of). And finally, take ?.index to get the index of the first entry that satisfies the condition, or null if none satisfy.
val x = 4
val p = 3
val list = listOf(2,5,3,6,0,6,7)
val t = list
.windowed(p)
.withIndex()
.firstOrNull { (_, sublist) -> sublist.all { it >= x } }
?.index
find Returns the first element matching the given predicate, or null if no such element was found.
If I've understood correctly, this should work:
fun main() {
val list = listOf(3,5,3,6,0,6,7)
val p = 2
val x = 4
val t = list.withIndex().windowed(p).firstOrNull() { window ->
window.all { it.value >= x }
}?.first()?.index
println(t)
}
Output:
5

zip with next value with kotlin Flow

how to zip a Flow with the next value as zipWithNext operator for collections?
zipWithNext behaves like:
val letters = ('a'..'f').toList()
val pairs = letters.zipWithNext()
println(letters) // [a, b, c, d, e, f]
println(pairs) // [(a, b), (b, c), (c, d), (d, e), (e, f)]
but in my case letters would be:
val letters = flowOf('a'..'f')
bonus points:
i tried flowOf(1, 2, 3).scan(emptyList<Int>()) { acc, value -> acc + value }.toList() on https://play.kotlinlang.org/ but doesn't find flowOf what import or else i'm missing there?
One possible solution is:
val letters = ('a'..'f').toList().toTypedArray()
val lettersFlow = flowOf(*letters)
val result = lettersFlow.scan(Pair<Char, Char>('a','a')) { acc, value -> Pair(acc.second, value) }.drop(2).toList()
println(result)