How can I merge multiple overlapping date ranges and create new ones? - algorithm

I have multiple date ranges each with a start and end date/time, containing a single value from which I want to create new ranges, where the overlapping range values are appended to a slice.
Date/time Ranges are the following:
[10:00, 10:15] = 7
[10:10, 10:20] = 9
[10:05, 10:25] = 2
[11:00, now] = 3
To illustrate it better please see the following image (I used only times here, to simplify it):
On the image a date range [10:00, 10:15] contains the value 7, [10:10, 10:20] = 9 and so on.
I would need to generate the following date ranges, where overlapping range values gets merged together:
[10:00, 10:05] = 7
[10:05, 10:10] = 7,2
[10:10, 10:15] = 7,2,9
[10:15, 10:20] = 2,9
[10:20, 10:25] = 2
[10:25, 11:00] = 2 <-- this was a gap, no overlap and not continuous.
[11:00, now] = 3
I used a struct to represent a range
type Range struct {
Start time.Time
End time.Time
Values []int
}
Is there an easy and efficient way of doing this?

Here's a sketch of an algorithm to do this:
The data struct would be:
type Boundary struct {
Time time.Time
AddRemove int
Value int
}
A Boundary would represent a Value added or removed from the list of values at a given time. For a range:
[from,to]=number
you create two Boundary objects:
b1:=Boundary{Time:from,AddRemove: 1, Value: number}
b2:=Boundary{Time:to,AddRemove:-1,Value:number}
You can then sort all boundary objects by time and AddRemove. If times are equal, you should process adds first, then removes. Once this is done, you can process the boundary objects, and create your ranges:
last:=time.Time{}
values:=map[int]struct{}{}
for _,b:=range boundaries {
if last.IsZero() {
last=b.Time
values[b.Value]=struct{}{}
} else {
// Create a new range here with [last,b.Time] with values given in `values`
if b.AddRemove==1 {
values[b.Value]=struct{}{}
} else {
delete(values,b.Value)
}
last=b.Time
}
}

Related

Answering the Longest Substring Without Repeating Characters in Kotlin

I've spend some time working on the problem and got this close
fun lengthOfLongestSubstring(s: String): Int {
var set = HashSet<Char>()
var initalChar = 0
var count = 0
s.forEach {r ->
while(!set.add(s[r]))
set.remove(s[r])
initalChar++
set.add(s[r])
count = maxOf(count, r - initialChar + 1)
}
return count
}
I understand that a HashSet is needed to answer the question since it doesn't allow for repeating characters but I keep getting a type mismatch error. I'm not above being wrong. Any assistance will be appreciated.
Your misunderstanding is that r represents a character in the string, not an index of the string, so saying s[r] doesn't make sense. You just mean r.
But you are also using r on its own, so you should be using forEachIndexed, which lets you access both the element of the sequence and the index of that element:
s.forEach { i, r ->
while(!set.add(r))
set.remove(r)
initialChar++
set.add(r)
count = maxOf(count, i - initialChar + 1)
}
Though there are still some parts of your code that doesn't quite make sense.
while(!set.add(r)) set.remove(r) is functionally the same as set.add(r). If add returns false, that means the element is already in the set, you remove it and the next iteration of the loop adds the element back into the set. If add returns true, that means the set didn't have the element and it was successfully added, so in any case, the result is you add r to the set.
And then you do set.add(r) again two lines later for some reason?
Anyway, here is a brute-force solution that you can use as a starting point to optimise:
fun lengthOfLongestSubstring(s: String): Int {
val set = mutableSetOf<Char>()
var currentMax = 0
// for each substring starting at index i...
for (i in s.indices) {
// update the current max from the previous iterations...
currentMax = maxOf(currentMax, set.size)
// clear the set to record a new substring
set.clear()
// loop through the characters in this substring
for (j in i..s.lastIndex) {
if (!set.add(s[j])) { // if the letter already exists
break // go to the next iteration of the outer for loop
}
}
}
return maxOf(currentMax, set.size)
}

Efficient log parsing in golang

What would be an efficient (performance and readability) of parsing lines in a log file and extracting points of interest?
For example:
*** Time: 2/1/2019 13:51:00
17.965 Pump 10 hose FF price level 1 limit 0.0000 authorise pending (Type 00)
17.965 Pump 10 State change LOCKED_PSTATE to CALLING_PSTATE [31]
38.791 Pump 10 delivery complete, Hose 1, price 72.9500, level 1, value 100.0000, volume 1.3700, v-total 8650924.3700, m-total 21885705.8800, T13:51:38
Things I need to extract are 10 (for pump 10), Price Level. Limit
The _PSTATE changes the values from the delivery completel line etc.
Currently I'm using a regular expression to capture each one and using capture groups. But it feels inefficient and there is quite a bit of duplication.
For example, I have a bunch of these:
reStateChange := regexp.MustCompile(`^(?P<offset>.*) Pump (?P<pump>\d{2}) State change (?P<oldstate>\w+_PSTATE) to (?P<newstate>\w+)_PSTATE`)
Then inside a while loop
if match := reStateChange.FindStringSubmatch(text); len(match) > 0 {
matched = true
for i, name := range match {
result[reStateChange.SubexpNames()[i]] = name
}
} else if match := otherReMatch.FindStringSubmatch(text); len(match) > 0 {
matched = true
for i, name := range match {
result[reStateChange.SubexpNames()[i]] = name
}
} else if strings.Contains(text, "*** Time:") {
}
It feels that there could be a much better way to do this. I would trade some performance for readability. The log files are only really 10MB max. Often smaller.
I'm after some suggestions on how to make this better in golang.
If all your log lines are similar to that sample you posted, they seem quite structured so regular expressions might be a bit overkill and hard to generalize.
Another option would be for you to transform each of those lines to a slice of strings ([]string) by using strings.Fields, or even strings.FieldFunc so that you can strip both white space and commas.
Then you can design an interface like:
type LogLineProcessor interface {
CanParse(line []string)
GetResultFrom(line []string) LogLineResult
}
Where LogLineResult is an struct containing the extracted information.
You can then define multiple structs with methods that implement LogLineProcessor (each implementation would look at specific positions on that []string to realize if it is a line it can process or not, like looking for the words "hose", "FF" and "price" in the positions it expects to find them).
The GetResultFrom implementations would also extract each data point from specific positions in the []string (it can rely on that information being there if it already determined it was one of the lines it can process).
You can create a var processors []LogLineProcessor, put all your processors in there and then just iterate that array:
line := strings.Fields(text)
for _, processor := range processors {
if processor.CanParse(line) {
result := processor.GetResultFrom(line)
// do whatever needed with the result
}
}

Insert a map into other map with a unique type key

hello guys i am new to maps in C++ i am having a question regarding copying a particular type map to another map of same kind the details are shown below
I initially declared a map like this
map<string,int> objmap,obj_porcess ;
for(int i = 0; i < 10]; i++) {
obj_process[to_string(i)]=i+10//some processing the to_string is just in case but i have strings with names for all 10 values
}
like
obj_process["today"]=1;
obj_process["yesterday"]=-1;
obj_process["tommorow"]=2;
now i want to define some thing like this just my key word should be added with the process and remaining all can be same for all the keys from obj_process
objmap["process_"+"today"] = obj_process["today"];
instead of defining all 10 can i have a simple code cause in here i took an example of 10 but i have like 200 set of different strings in the key of map
I think this is what you need:
map<string,int> objmap;
map<string,int> obj_porcess;
//
// Fill up the contents of obj_porcess
//
// Copy objects from obj_porcess to objmap using a computed key.
for ( auto& item : obj_process )
{
objmap[std::string("process_") + item.first] = item.second;
}
Could you iterate over the map?
for(auto &i : obj_process)
objmap["process" + i.first] = i.second;

How to return-7-6-5-4-3-2-1012345678910111213

Code below is in Objective C in Xcode. I am trying to return -7-6-5-4-3-2-1012345678910111213 as the method is expecting that response. number = -7 and otherNumber = 13 How do I return the series of numbers? I tried the method below but with no success...
while (number < otherNumber) {
++number;
return number;
}
Another thing to look out for is how your parameters are getting passed in to the method. Since we dont know if "number" is always going to be less than "otherNumber" you should check to find out which of the two numbers being passed in is lower before using them in your while loop.
this is very similar to the previous post but it might make it a tad clearer:
//find which number is low and which is high and set it accordingly
while (low <= high){
//then append low to end of string
++low;
}
//return your string
And this handles the case when the numbers are equal
In Objective-C, methods can only have one return value.
If your method returns an array, something like this would work:
// Create an NSMutableArray
while (number < otherNumber) {
// Add the number to the array
++number;
}
// Return the array
Or, similarly, if your method returns a string:
// Create an NSMutableString
while (number < otherNumber) {
// Append the number to the end of the string
++number;
}
// Return the string
A few notes:
your conditional, number < otherNumber, won't capture the case where number == otherNumber. Since in your example otherNumber is 13, and you want that included, you may want to use number <= otherNumber.
you can only compare scalar numbers (like NSInteger or CGFloat) with the inequality operators (like < and >). However, you can only add objects to NSMutableArray and NSMutableString. So you'll need to convert between the scalar numbers and NSNumber as appropriate.
Since it looks like you're learning Objective-C, note that this is different from Swift, which does allow methods to return multiple values.

VB Console - how to get multiple input in the same line, split and store to list

Say i want to get all the numbers a user inputs in the console.
15,30 45
then I want to then split the 'string' of numbers into different substrings and store it into an array of string or list of type string. Also i want to get the max min avg and total.
Should i store the substring in a array or generic list? I prefer to store it in a list so that i can get the avg and total using list.avg and list.sum
In order to get max min avg and sum, should i convert each element into an integer or convert the whole list to another type? If so, how do i convert?
EDIT: Is there any way to let the user edit the numbers if somehow he mixed a letter or symbol?
First, you can also get the avarage or sum if its a int[] instead of List<int> since Enumerable.Sum or Enumerable.Average takes an IEnumerable<T>. So the decision depends on if you need to modify the collection afterwards. Do you want to add or remove items from it later? Then use a generic List<T>.
string input = "15,30 45";
int i = int.MinValue;
List<int> result = input.Split(new[]{' ', ','}, StringSplitOptions.RemoveEmptyEntries)
.Where(str => int.TryParse(str, out i))
.Select(str => i)
.ToList();
double avg = result.Average();
int sum = result.Sum();
You could try with this code
void Main()
{
double temp;
List<double> input = new List<double>();
string line = Console.ReadLine();
string[] parts = line.Split(' ');
foreach(string p in parts)
{
if(double.TryParse(p, out temp))
input.Add(temp);
}
double sum = input.Sum();
Console.WriteLine(sum);
}
Here I get the input from the Console.ReadLine and split the line at the space separator. Every line subpart is converted to a double value (only if it is possible to convert to a double according to your locale settings) and added to a List<double> . At this point is really simple to obtain the information you need (IEnumerable.Sum, IEnumerable.Average, etc..)

Resources