Process the same input file concurrently Let's say we have a text file that contains 2 different types of lines. For the sake of example, one group starts with "i:" (for Integer) and the other group starts with "s:" (for String), something like the following file: s:New york s:Apple i:387548 s:Amsterdam i:4556 i:39874 s:Orange i:56787 s:Banana i:4657567 s:Turkey i:45679456 s:Iran i:4356456 i:23423 i:456 s:Ukraine i:453645 i:5456 We want to process these input lines separately but concurrently. And the process can be anything, for this example, we just print them to the console. But what matters is that we open the file only for READ so 2 different processes (or routines) can read the file at the same time. The Cats Effect answer to open files (or in general any resources) in a safe and efficient way, is Resource class. So we need a function to take the path to the file and give us a Resource of some type that allows us to read the file line by line. One o...
Algorithm: Find a pair in an array of numbers for a given sum
Given an Array (or List) and a sum, we want to find a pair of numbers whose sum will be equal to the given sum.
For example for the [1,4,7] and 5 the outcome should be pair of 1 and 4. Or for [5, 7, 2, 8, 3] and 15 the outcome should be pair of 7 and 8.
Both pairs of 1 and 5, and 2 and 4 are correct for the input of [2, 4, 1, 5] and 6.
The function signature looks like this:
def findPairForSum(list: List[Int], sum: Int): Option[(Int, Int)] = ???The return type is Option[(Int, Int)] because there might be no pair at all.
There are two approaches to solving this problem:
- The brute force approach which is the simplest and most naive one
- The first sort approach which is more efficient and a bit more complex
Naive approach
We can check the given sum against all possible pair combinations. In imperative programming, it would be the famous i and j for loops. But in functional programming, we can implement this using recursion.
In our function, we write 2 nested functions, one for checking if the sum of two numbers is equal to the third argument. We call it check
def check(a: Int, b: Int, sum: Int): Boolean = a + b == sumThe second nested function is our recursive function which as a convention we usually call it loop.
So our complete function will look like this
def findPairForSumNaive(list: List[Int], sum: Int): Option[(Int, Int)] = {
def check(a: Int, b: Int, sum: Int): Boolean = a + b == sum
def loop(list: List[Int], sum: Int, index: Int): Option[(Int, Int)] = {
list match
case List(_) | Nil => None
case _ =>
if (index < list.length) {
if (check(list.head, list(index), sum)) Some(list.head, list(index))
else loop(list, sum, index + 1)
} else {
loop(list.tail, sum, 1)
}
}
loop(list, sum, 1)
}Smart approach
In this approach, we first sort the given Array (or List) and then choose a high index (last element) and a low index (first element). We compare the given sum with the high and low elements' sum, if the given sum is bigger we increase the low index, and if it is smaller, we decrease the high index. If they are equal we have found our pair.
def findPairForSum(list: List[Int], sum: Int): Option[(Int, Int)] = {
def loop(sortedList: List[Int], sum: Int, lowIndex: Int, highIndex: Int): Option[(Int, Int)] = {
if (lowIndex == highIndex) None
else {
val low = sortedList(lowIndex)
val high = sortedList(highIndex)
if (low + high > sum)
loop(sortedList, sum, lowIndex, highIndex - 1)
else if (low + high < sum)
loop(sortedList, sum, lowIndex + 1, highIndex)
else
Some((low, high))
}
}
loop(list.sorted, sum, 0, list.length - 1)
}We can test our functions like this:
def main(args: Array[String]): Unit = {
val list = List(10, 3, 7, 9, 2)
val sum = 5
println(findPairForSumNaive(list, sum))
println(findPairForSum(list, sum))
}
Comments
Post a Comment