I am wondering what is the canonical approach to solve the following problem in Rx: Say I have two observables, mouse_down and mouse_up, whose elements represent mouse button presses. In a very simplistic scenario, if I wanted to detect a long press, I could do it the following way (in this case using RxPy, but conceptually the same in any Rx implementation):
mouse_long_press = mouse_down.delay(1000).take_until(mouse_up).repeat()
However, problems arise when we need to hoist some information from the mouse_down observable to the mouse_up observable. For example, consider if the elements of the observable stored information about which mouse button was pressed. Obviously, we would only want to pair mouse_down with mouse_up of the corresponding button. One solution that I came up with is this:
mouse_long_press = mouse_down.select_many(lambda x:
rx.Observable.just(x).delay(1000)\
.take_until(mouse_up.where(lambda y: x.button == y.button))
)
If there is a more straight forward solution, I would love to hear it - but as far as I can tell this works. However, things get more complicated, if we also want to detect how far the mouse has moved between mouse_down and mouse_up. For this we need to introduce a new observable mouse_move, which carries information about the mouse position.
mouse_long_press = mouse_down.select_many(lambda x:
mouse_move.select(lambda z: distance(x, z) > 100).delay(1000)\
.take_until(mouse_up.where(lambda y: x.button == y.button))
)
However, this is pretty much where I get stuck. Whenever a button is held down longer than 1 second, I get a bunch of boolean values. However, I only want to detect a long press when all of them are false, which sounds like the perfect case for the all operator. It feels like there's only a small step missing, but I haven't been able to figure out how to make it work so far. Perhaps I am also doing things in a backwards way. Looking forward to any suggestions.
Ok, I guess I found a possible answer. RxPy has a take_with_time operator, which works for this purpose. Not really as straight-forward as I was hoping for (not sure if the take_with_time is avaliable in other Rx implementations).
mouse_long_press = mouse_down.select_many(lambda x:
mouse_moves.take_with_time(1000).all(lambda z: distance(x, z) < 100)\
.take_until(mouse_up.where(lambda y: x.button == y.button))
)
I will leave the question open for now in case somebody has a better suggestion.
I'd approach the problem differently, by creating a stream of mouse presses with length information, and filtering that for presses longer than 1s.
First let's assume that you only have one mouse button. Merge the mouse_up and mouse_down streams and assign time intervals between them with the time_interval() operator. You will get a stream of intervals since previous event, along with the event itself. Assuming your mouse-ups and mouse-downs alternate, this means your events now are:
(down + time since last up), (up + time since last down), (down + time since last up) ...
Now, simply filter for x.value.type == "up" and x.interval > datetime.timedelta(seconds=1)
(You can also validate this with pairwise(), which always gives you the current + previous event, so you can check that the previous one is down and the current one is up.)
Second, add the mouse movement information, using the window() operator.
(This part is untested, I'm going off the docs of how it's supposed to behave, but the docs aren't very clear. So YMMV. )
The idea is that you can collect sequences of events from an observable, separated into groups based on another observable. From the docs:
The window_openings observable is going to be the merged up/down stream, or the interval stream, whichever is more convenient. Then you can flat_map() (or select_many, which is the same thing) the result and work out the distance in whichever way you like.
Again, you should end up with a stream of distances between up/down events. Then you can zip() this stream with the interval stream, at which point you can filter for up events and get both time and distance until the previous down.
Third, what if you are getting events for multiple mouse buttons?
Simply use group_by() operator to split into per-button streams and proceed as above.
Full code below:
Event = collections.NamedTuple("Event", "event interval distance")
def sum_distance(move_stream):
# put your distance calculation here; something like:
return move_stream.pairwise().reduce(lambda acc, (a, b): acc + distance(a, b), 0)
def mouse_press(updown_stream):
# shared stream for less duplication
shared = updown_stream.share()
intervals = shared.time_interval() # element is: (interval=timedelta, value=original event)
distances = mouse_move.window(shared).flat_map(sum_distance)
zipped = intervals.zip(distances, lambda i, d: \
Event(i.value, i.interval, d) )
mouse_long_press = (
# merge the mouse streams
rx.Observable.merge(mouse_up, mouse_down)
# separate into streams for each button
.group_by(lambda x: x.button)
# create per-button event streams per above and merge results back
.flat_map(mouse_press)
# filter by event type and length
.filter(lambda ev: ev.event.type == "up" and ev.interval >= datetime.timedelta(seconds=1)
)
Related
I'm working on a project where i have a window with a size of 4 days, with a step of 1 day
.timewindow(Time.days(4), Time.days(1))
and i have also a trigger
.trigger(new myTrigger)
onEventTime ---> Continue
onProccessingTime ---> Continue
clear ---> Purge
onElement---> (if element.isFinalTransaction) TriggerResult.FIRE_AND_PRUGE
isFinalTransaction is a boolean, when true it call FAP.
the mean question is how can i make it return true/false depending on if the element is the last in the window or not
is there any method that can tell us if the current element is the last one in the window?
is there any method that can tell us if the current window is done (before sliding) or not ?
From the abstract trigger class (https://github.com/apache/flink/blob/master//flink-streaming-java/src/main/java/org/apache/flink/streaming/api/windowing/triggers/Trigger.java)
The short answer is no. The method onElement is called for every element that gets added to the pane. When an element gets added it's impossible to know if it is the last element, because that information is not known until the next element comes (and we see if it was in this window or the next one).
However, one alternative would be to check if the element is sufficiently close to the end of the end of the window (because onElement has access to window e.g. if (timestamp > window.getEnd - delta) ...
However, I can not think of a use case in which I would recommend this. If you need access to the last element in the window, you should probably just use a WindowFunction and in the apply method get the last element of the input iterable (input.last).
Before I spend a lot of time writing the only solution I can think of I was wondering if I'm doing it an inefficient way.
Once a support ticket is closed, a script is triggered, the script is passed an array of 'status-change-events' that happened from call open to close. So you might have 5 changes: new, open, active, stalled, resolved. Each one of these events has a timestamp associated with it.
What I need to do is calculate how much time the call was with us (new, open, active) and how much time it was with the customer (stalled). I also need to figure out how much of the 'us' time was within core hours 08:00 - 18:00 (and how many were non-core), and weekends/bank holidays count towards non-core hours.
My current idea is to for each status change, iterate over every second that occurred and check for core/non_core, and log it.
Here's some pseudo code:
time_since_last = ticket->creation_date
foreach events as event {
time_now = time_since_last
while (time_now < ticket->event_date) {
if ticket->status = stalled {
customer_fault_stalled++
} else {
work out if it was our fault or not
add to the appropriate counter etc
}
time_now++
}
}
Apologies if it's a little unclear, it's a fairly longwinded problem. Also I'm aware this may be slightly off of SO question guidelines, but I can't think of a better way of wording it and I need some advice before I spend days writing it this way.
I think you have the right idea, but recalculating the status of every ticket for every second of elapsed time will take a lot processing, and nothing will have changed for the vast majority of those one-second intervals
The way event simulations work, and the way I think you should write your application, is to create a list of all events where the status might change. So you will want to include all of the status change events for every ticket as well as the start and end of core time on all non-bank-holiday weekdays
That list of events is sorted by timestamp, after which you can just process each event as if your per-second counter has reached that time. The difference is that you no longer have to count through the many intervening seconds where nothing changes, and you should end up with a much more efficient application
I hope that's clear. You may find it easier to process each ticket separately, but the maximum gain will be achieved by processing all tickets simultaneously. You will still have a sorted sequence of events to process, but you will avoid having to reprocess the same core time start and end events over and over again
One more thing I noticed is that you can probably ignore any open status change events. I would guess that tickets either go from new to open and then active, or straight from new to resolved. So a switch between with your company and with the customer will never be made at an open event, and so they can be ignored. Please check this as I am only speaking from my intuition, and clearly know nothing about how your ticketing system has been designed
I would not iterate over the seconds. Depending on the cost of your calculations that could be quite costly. It would be better to calculate the borders between core/outside core.
use strict;
use warnings;
my $customer_time;
my $our_time_outside;
my $our_time_core;
foreach my $event ($ticket->events) {
my $current_ts = $event->start_ts;
while ($current_ts < $event->end_ts) {
if ($event->status eq 'stalled') {
$customer_time += $event->end_ts - $current_ts;
$current_ts = $event->end_ts;
}
elsif (is_core_hours($current_ts)) {
my $next_ts = min(end_of_core_hours($current_ts), $event->end_ts);
$our_time_core += $next_ts - $current_ts;
$current_ts = $next_ts;
}
else {
my $next_ts = min(start_of_core_hours($current_ts), $event->end_ts);
$our_time_outside += $next_ts - $current_ts;
$current_ts = $next_ts;
}
}
}
I can't see why you'd want to iterate over every second. That seems very wasteful.
Get a list of all of the events for a given ticket.
Add to the list any boundaries between core and non-core times.
Sort this list into chronological order.
For each consecutive pair of events in the list, subtract the later from the earlier to get a duration.
Add that duration to the appropriate bucket.
And the usual caveats for dealing with dates and times apply here:
Use a library (I recommend DateTime together with DateTime::Duration)
Convert all of your timestamps to UTC as soon as you get them. Only convert back to local time just before displaying them to the user.
Am i right in thinking that it is not possible to perform insertion sort on a singly linked list?
My reasoning: assuming that insertion sort by definition means that, as we move to the right in the outer loop, we move to the left in the inner loop and shift values up (to the right) as required and insert our current value when done with the inner loop. As a result an SLL cannot accomodate such an algorithm. Correct?
Well, I'd sound like the Captain Obvious, but the answer mostly depends on whether you're ok with keeping all iterations directed the same way as elements are linked and still implementing the proper sorting algorithm as per your definition. I don't really want to mess around your definition of insertion sorting, so I'm afraid you'd really have to think yourself. At least for a while. It's an homework anyway... ;)
Ok, here's what I got just before closing the page. You may iterate over an SLL in reversed direction, but this would take n*n/2 traversals to visit all the n elements. So you're theoretically okay with any traversal directions for your sorting loops. Guess it pretty much solves your question.
It is doable and is an interesting problem to explore.
The core of insertion sort algorithm is creating a sorted sequence with the first one element and extending it by adding new element and keeping the sequence is still sorted until it contains all the input data.
Singly linked list can not be traversed back, but you can always start from it's head to search the position for the new element.
The tricky part is when inserting node i before node j, you must handle their neighbor relationship well(I mean both node i and j's neighbor needs to be taken care of).
Here is my code. I hope it useful for you.
int insertSort(Node **pHead)
{
Node *current1 = (*pHead)->next;
Node *pre1 =*pHead;
Node *current2= *pHead;
Node *pre2=*pHead;
while(NULL!=current1)
{
pre2=*pHead;
current2=*pHead;
while((current2->data < current1->data))
{
pre2 = current2;
current2 = current2->next;
}
if(current2 != current1)
{
pre1->next=current1->next;
if(current2==*pHead)
{
current1->next=*pHead;
*pHead = current1;
}
else
{
pre2->next = current1;
current1->next = current2;
}
current1 = pre1->next;
}
else
{
pre1 = pre1->next;
current1 = current1->next;
}
}
return 0;
}
On Windows Phone 7 there is a new version of the BufferWithTimeOrCount extension method for IObservable that returns a "stream of streams" instead of the previous "stream of lists". I'm having difficulty trying to use either the new or old methods, so maybe I just don't understand how it works, but my goal is to create a stream that only fires when an existing stream matches a specified time based pattern during the previous 2 touch events. So far I have created streams for TouchUp and TouchDown (see related question) and In pseudo code I want something like:
//BufferLast2 should contain the last 1 or 2 touch events that occurred in the last 500ms. If no touches occurred this should return an empty set
var BufferLast2 = TouchDown.Merge(TouchUp).BufferWithTimeOrCount(TimeSpan.FromSeconds(0.5), 2);
//Use BufferLast2 to detect tap (TouchDown then TouchUp occuring in less than 0.5s)
var TouchTap = from touch2 in BufferLast2
where touch2.Count == 2 && touch2.First().Action == TouchAction.Down && touch2.Last().Action == TouchAction.Up
select touch2.First(); //returns initial TouchDown event
//Use BufferLast2 to detect Hold (TouchDown with no TouchUp occuring in 0.5s)
var TouchHold = from touch2 in BufferLast2
where touch2.Count == 1 && touch2.First().Action == TouchAction.Down
select touch2.First(); //returns initial TouchDown event
When using the "Stable" Microsoft.Phone.Reactive version of Rx that is built into the ROM calling IObservable<Class>.BufferWithTimeOrCount(...) returns a IObservable<IList<Class>>, which is pretty easy to work with using the standard list operators (as outlined above), but for some reason BufferLast2 was always returning two down events instead of the Down->Up sequence that I expected.
I figured it might be a bug in the code, so I tried adding a reference to the latest version of Rx and used the Observable Extensions from C:\Program Files (x86)\Microsoft Cloud Programmability\Reactive Extensions\v1.0.2838.0\WP7\System.Reactive.dll in which BufferWithTimeOrCount(...) returns a IObservable<IObservable<Class>>. This makes simple filters like Where x.Count == 2 or Where x.First().P == ... much harder to write. I haven't actually figured out how to do a simple filter like x.Count() == 2 on this return value without creating a completely separate subscription or Subject object, which seams way too complex. It's probably a simple error like my last question (all I needed was a Where clause :-P) but it is really driving me bonkers. Any help?
Changing the api makes the buffering look more Rx-y and fits with their Window operator implementation (wouldn't be surprised if using reflector you'd be able to see the Buffer operators using Window). I would think there's probably a variety of reasons that they've changed it. I'm not going to second guess them as they're a lot smarter than me!
So here's my stab at a solution. There may be a cleaner way to get what you're after but i'd probably implement my own extention method to buffer into a list. Maybe something like:
public static class BufferToList
{
public static IObservable<IEnumerable<TSource>> BufferToList<TSource>(this IObservable<TSource> source)
{
return Observable.CreateWithDisposable<IEnumerable<TSource>>(observer =>
{
var list = new List<TSource>();
return source.Subscribe(list.Add,
observer.OnError,
() =>
{
observer.OnNext(list);
observer.OnCompleted();
});
});
}
}
Then something like:
TouchDown.Merge(TouchUp)
.BufferWithTimeOrCount(TimeSpan.FromSeconds(0.5), 2)
.Select(bufferedValues => bufferedValues.BufferToList())
.Subscribe(OnBufferOpen)
private void OnBufferOpen(IObservable<IEnumerable<IEvent<IEventArgs>>> bufferedListAsync)
{
bufferedListAsync.Where(list => list.Count() == 2);
}
I suggest if you want a full explanation of why they've changed the api, go and ask the question over on the rx forums on msdn
The latest release of Rx, v1.0.2856.0, provides both buffers and windows. For the buffers, we restored the original signatures, based on IList. The corresponding window operators will return nested observable sequences.
The way the Buffer* operators are implemented is by composing the corresponding Window* operator with the new ToList extension method that takes an IObservable into an IObservable>. All the Buffer* operator does is invoke this new ToList operator in a SelectMany selector.
I am using numeric updowncontrol. For min and max values changed listening for these events
this.numDownMinLimit.ValueChanged += new System.EventHandler(this.numDownMinLimit_ValueChanged);
this.numDownMaxLimit.ValueChanged += new System.EventHandler(this.numDownMaxLimit_ValueChanged);
step size set is 0.1
The eventhandler takes some time to complete.
If you keep the mouse pressed for a period of time and then release it, the eventhandler still executes with the previous values which were fired.
How do we prevent this scenario from occurring? I would like to discard the remaining events which are still in the queue, waiting to be handled, when the user releases the mouse button.
You need to have a look at the NumericUpDownAcceleration Class which handles this behaviour:
From: http://msdn.microsoft.com/en-us/library/system.windows.forms.numericupdownacceleration.aspx
The NumericUpDownAcceleration object
is used by the NumericUpDown control
to optionally provide acceleration
when incrementing or decrementing the
control through a large quantity of
numbers.
Let us know how you get on.