How to get historical data from a PublishSubject? - reactive-programming

How to get all historical data from a PublishSubject?
val ob = PublishSubject[Int]()
ob.subscribe(x => println("a: " + x))
ob.onNext(1)
ob.subscribe(x => println("b: " + x))
ob.onNext(2)
It prints:
a: 1
a: 2
b: 2
You can see there is no b: 1 printed.
If I have to use PublishSubject (since I need to update an observable from multi places), how can I make sure later subscribers can also get the all historical data?

Related

Index of users distributed across rooms

I am new to stackoverflow so please guide me if I explain my problem inappropriately.
I have a collection of integers of length N (an Array[Int]) where each element at some index i represents number of users present in room Ri. In room Ri, the users are also indexed such that indexing of users in the first room is from 1 to R1, second room contains R1 + 1 to R1 + R2 and so on.
Now the input is the index of user and I need to find out in which room the user is present.
My solution goes like this:
def getRoomNumber(userIndex: Int, userDistribution: Array[Int]): Int = {
val cummulativeRooms: Array[Int] =
rooms.tail.scanLeft(rooms.head)((x, y) => x + y)
val roomIndex = cummulativeRooms.takeWhile(_ < userIndex).length + 1
roomIndex
}
Here, as the user 4 will be present in room 2 (because rooms have user distribution like this: Room1(U1, U2), Room2(U3, U4, U5)).
My code is working fine for this input. But I have some hidden test cases out of which half of them passed. But later half does not and some even throws an exception.
Can anyone please tell me what is the problem in my code. Also do you have any other algorithm to do it which is more efficient than this.
More Explanation -
Lets say I have 10 users - U1, U2, U3, U4, U5 and we separate them into N rooms in a sequence which is defined by the userDistribution array - Array(2, 3). This means that users U1 and U2 will be present in room 1 & users from U3 to U5 will be present in room 2.
Now, if I want to find out where the user U4 is, so the output should be 2. Inputs are the user index i.e. 4 in this case and userDistribution array - Array(2, 3)
EDIT: Code changed to a function. The inputs are the user index we want to find and userDistributions containing the number of users present in each room sequentially.
EDIT: Constraints are (We don't have to check for these contraints in our code) -
Both N and Ui can have values between 1 to 10e5.
Also, the Ui will be less than sum of the the array.
If I understand the problem correctly, you only need to iterate the user's distribution array and keep a sum of how many users you have seen until that sum is greater than or equals to the target user.
You can do that pretty easily using an imperative solution:
// Return Option because we can not guarantee the constraints.
// Also, ArraySeq is just an immutable array.
def imperativeSolution(userDistribution: ArraySeq[PositiveInt])(targetUser: PositiveInt): Option[PositiveInt] = {
var acc = 0
for (i <- userDistribution.indices) {
acc += userDistribution(i)
if (targetUser <= acc) return Some(i + 1)
}
None
}
However, this is quite "ugly" because of the mutability and the use of return.
We may rather use a recursive approach:
// It is better to use a recursive data structure like List for a recursive algorithm.
def recursiveSolution(userDistribution: List[PositiveInt])(targetUser: PositiveInt): Option[PositiveInt] = {
#annotation.tailrec
def loop(remaining: List[PositiveInt], idx: PositiveInt, acc: PositiveInt): Option[PositiveInt] =
remaining match {
case x :: xs =>
val newAcc = acc + x
if (targetUser <= newAcc) Some(idx)
else loop(remaining = xs, idx + 1, newAcc)
case Nil =>
None
}
loop(remaining = userDistribution, idx = 1, acc = 0)
}
This is immutable but it has a lot of boilerplate, which we may reduce and be more expressive using a more functional solution:
def functionalSolution(userDistribution: IterableOnce[PositiveInt])(targetUser: PositiveInt): Option[PositiveInt] =
userDistribution
.iterator
.scanLeft(0)(_ + _)
.zipWithIndex
.collectFirst {
case (acc, idx) if (targetUser <= acc) => idx
}
You can see them running here.

Scala: Add a sequence number to duplicate elements in a list

I have a list and want to add a sequential number to duplicate elements.
val lst=List("a", "b", "c", "b", "c", "d", "b","a")
The result should be
List("a___0", "b___0", "c____0", "b___1", "c____1", "d___0", "b___2","a___1")
preserving the original order.
What I have so far:
val lb=new ListBuffer[String]()
for(i<-0 to lst.length-2) {
val lbSplit=lb.map(a=>a.split("____")(0)).distinct.toList
if(!lbSplit.contains(lst(i))){
var count=0
lb+=lst(i)+"____"+count
for(j<-i+1 to lst.length-1){
if(lst(i).equalsIgnoreCase(lst(j))) {
count+=1
lb+= lst(i)+"____"+count
}
}
}
}
which results in :
res120: scala.collection.mutable.ListBuffer[String]
= ListBuffer(a____0, a____1, b____0, b____1, b____2, c____0, c____1, d____0)
messing up the order. Also if there is a more concise way that would be great.
This should work without any mutable variables.
val lst=List("a", "b", "c", "b", "c", "d", "b","a")
lst.foldLeft((Map[String,Int]().withDefaultValue(0),List[String]())){
case ((m, l), x) => (m + (x->(m(x)+1)), x + "__" + m(x) :: l)
}._2.reverse
// res0: List[String] = List(a__0, b__0, c__0, b__1, c__1, d__0, b__2, a__1)
explanation
lst.foldLeft - Take the List of items (in this case a List[String]) and fold them (starting on the left) into a single item.
(Map[String,Int]().withDefaultValue(0),List[String]()) - In this case the new item will be a tuple of type (Map[String,Int], List[String]). We'll start the tuple with an empty Map and an empty List.
case ((m, l), x) => - Every time an element from lst is passed in to the tuple calculation we'll call that element x. We'll also receive the tuple from the previous calculation. We'll call the Map part m and we'll call the List part l.
m + (x->(m(x)+1)) - The Map part of the new tuple is created by creating/updating the count for this String (the x) and adding it to the received Map.
x + "__" + m(x) :: l - The List part of the new tuple is created by pre-pending a new String at the head.
}._2.reverse - The fold is finished. Extract the List from the tuple (the 2nd element) and reverse it to restore the original order of elements.
I think a more concise way that preserves the order would just to be to use a Map[String, Int] to keep a running total of each time you've seen a particular string. Then you can just map over lst directly and keep updating the map each time you've seen a string:
var map = Map[String, Int]()
lst.map { str =>
val count = map.getOrElse(str, 0) //get current count if in the map, otherwise zero
map += (str -> (count + 1)) //update the count
str + "__" + count
}
which will give you the following for your example:
List(a__0, b__0, c__0, b__1, c__1, d__0, b__2, a__1)
I consider that easiest to read, but if you want to avoid var then you can use foldLeft with a tuple to hold the intermediate state of the map:
lst.foldLeft((List[String](), Map[String, Int]())) { case ((list, map), str) =>
val count = map.getOrElse(str, 0)
(list :+ (str + "__" + count), map + (str -> (count + 1)))
}._1

Is the Writer Monad effectively the same as the State Monad?

There's a great tutorial here that seems to suggest to me that the Writer Monad is basically a special case tuple object that does operations on behalf of (A,B). The writer accumulates values on the left (which is A) and that A has a corresponding Monoid with it (hence it can accumulate or mutate state). If A is a collection, then it accumulates.
The State Monad is also a object that deals with an internal tuple. They both can be flatMap'd, map'd, etc. And the operations seem the same to me. How are they different? (please respond back with a scala example, I'm not familiar with Haskel). Thanks!
Your intuition that these two monads are closely related is exactly right. The difference is that Writer is much more limited, in that it doesn't allow you to read the accumulated state (until you cash out at the end). The only thing you can do with the state in a Writer is tack more stuff onto the end.
More concisely, State[S, A] is a kind of wrapper for S => (S, A), while Writer[W, A] is a wrapper for (W, A).
Consider the following usage of Writer:
import scalaz._, Scalaz._
def addW(x: Int, y: Int): Writer[List[String], Int] =
Writer(List(s"$x + $y"), x + y)
val w = for {
a <- addW(1, 2)
b <- addW(3, 4)
c <- addW(a, b)
} yield c
Now we can run the computation:
scala> val (log, res) = w.run
log: List[String] = List(1 + 2, 3 + 4, 3 + 7)
res: Int = 10
We could do exactly the same thing with State:
def addS(x: Int, y: Int) =
State((log: List[String]) => (log |+| List(s"$x + $y"), x + y))
val s = for {
a <- addS(1, 2)
b <- addS(3, 4)
c <- addS(a, b)
} yield c
And then:
scala> val (log, res) = s.run(Nil)
log: List[String] = List(1 + 2, 3 + 4, 3 + 7)
res: Int = 10
But this is a little more verbose, and we could also do lots of other things with State that we couldn't do with Writer.
So the moral of the story is that you should use Writer whenever you can—your solution will be cleaner, more concise, and you'll get the satisfaction of having used the appropriate abstraction.
Very often Writer won't give you all the power you need, though, and in those cases State will be waiting for you.
tl;dr State is Read and Write while Writer is, well, only write.
With State you have access to the previous data stored and you can use this data in your current computation:
def myComputation(x: A) =
State((myState: List[A]) => {
val newValue = calculateNewValueBasedOnState(x,myState)
(log |+| List(newValue), newValue)
})
With Writer you can store data in some object you don't have access to, you can only write to that object.

How to fix my Fibonacci stream in Scala

I defined a function to return Fibonacci stream as follows:
def fib:Stream[Int] = {
Stream.cons(1,
Stream.cons(2,
(fib zip fib.tail) map {case (x, y) => println("%s + %s".format(x, y)); x + y}))
}
The functions work ok but it looks inefficient (see the output below)
scala> fib take 5 foreach println
1
2
1 + 2
3
1 + 2
2 + 3
5
1 + 2
1 + 2
2 + 3
3 + 5
8
So, it looks like the function calculates the n-th fibonacci number from the very beginning. Is it correct? How would you fix it?
That is because you have used a def. Try using a val:
lazy val fib: Stream[Int]
= 1 #:: 2 #:: (fib zip fib.tail map { case (x, y) => x + y })
Basically a def is a method; in your example you are calling the method each time and each time the method call constructs a new stream. The distinction between def and val has been covered on SO before, so I won't go into detail here. If you are from a Java background, it should be pretty clear.
This is another nice thing about scala; in Java, methods may be recursive but types and values may not be. In scala both values and types can be recursive.
You can do it the other way:
lazy val fibs = {
def f(a: Int, b: Int): Stream[Int] = a #:: f(b, a + b)
f(0, 1)
}

How do I populate a list of objects with new values

Apologies: I'm well noob
I have an items class
class item(ind:Int,freq:Int,gap:Int){}
I have an ordered list of ints
val listVar = a.toList
where a is an array
I want a list of items called metrics where
ind is the (unique) integer
freq is the number of times that ind appears in list
gap is the minimum gap between ind and the number in the list before it
so far I have:
def metrics = for {
n <- 0 until 255
listVar filter (x == n) count > 0
}
yield new item(n, (listVar filter == n).count,0)
It's crap and I know it - any clues?
Well, some of it is easy:
val freqMap = listVar groupBy identity mapValues (_.size)
This gives you ind and freq. To get gap I'd use a fold:
val gapMap = listVar.sliding(2).foldLeft(Map[Int, Int]()) {
case (map, List(prev, ind)) =>
map + (ind -> (map.getOrElse(ind, Int.MaxValue) min ind - prev))
}
Now you just need to unify them:
freqMap.keys.map( k => new item(k, freqMap(k), gapMap.getOrElse(k, 0)) )
Ideally you want to traverse the list only once and in the course for each different Int, you want to increment a counter (the frequency) as well as keep track of the minimum gap.
You can use a case class to store the frequency and the minimum gap, the value stored will be immutable. Note that minGap may not be defined.
case class Metric(frequency: Int, minGap: Option[Int])
In the general case you can use a Map[Int, Metric] to lookup the Metric immutable object. Looking for the minimum gap is the harder part. To look for gap, you can use the sliding(2) method. It will traverse the list with a sliding window of size two allowing to compare each Int to its previous value so that you can compute the gap.
Finally you need to accumulate and update the information as you traverse the list. This can be done by folding each element of the list into your temporary result until you traverse the whole list and get the complete result.
Putting things together:
listVar.sliding(2).foldLeft(
Map[Int, Metric]().withDefaultValue(Metric(0, None))
) {
case (map, List(a, b)) =>
val metric = map(b)
val newGap = metric.minGap match {
case None => math.abs(b - a)
case Some(gap) => math.min(gap, math.abs(b - a))
}
val newMetric = Metric(metric.frequency + 1, Some(newGap))
map + (b -> newMetric)
case (map, List(a)) =>
map + (a -> Metric(1, None))
case (map, _) =>
map
}
Result for listVar: List[Int] = List(2, 2, 4, 4, 0, 2, 2, 2, 4, 4)
scala.collection.immutable.Map[Int,Metric] = Map(2 -> Metric(4,Some(0)),
4 -> Metric(4,Some(0)), 0 -> Metric(1,Some(4)))
You can then turn the result into your desired item class using map.toSeq.map((i, m) => new Item(i, m.frequency, m.minGap.getOrElse(-1))).
You can also create directly your Item object in the process, but I thought the code would be harder to read.