Slice of array time.Time in Ascending order validation - go

For some time now I've been trying to create a function that validates a variable of the type [][2]time.Time. The columns of the array represet a pair of time.Time which are an input date and an outbound date respectively.but I can't produce code that addresses all possible invalid combinations and at the same time does not invalidate combinations that are actually valid.
The rules to invalidate are:
Dates cannot be longer than the current date and time.
Times can't be the same. E.g: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC)}}. Or [][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}}
There cannot be a new entry if there is no output before. E.g:
[][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Time{}//Default}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)} }
The dates must be in ascending order, that is, the first slice date that in this case represents an entry must be older than the second, the second older than the third, and so on. Therefore, below would be examples of invalid combinations:
[][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 7, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)} }.
What has caused me the biggest problem are the default values, because they are valid Time objects but they should be considered as null, that is, that the output date was not reported.
Imagine as if it were a point sheet of a worker, if there is an entry date but the output is default means that the worker entered but has not yet left, that is, it is a valid situation. But it would not be valid for a worker to register a new entry if there is not yet an output for their previous entry.
That's the code I've been able to produce so far. Yes, it's not complete because I've modified it so many times I don't know how to move forward anymore.
func validSliceArrayTime(slarti [][2]time.Time) bool {
now_time := time.Now()
var rtime, ltime time.Time
var rt_is_def bool
for _, v := slarti {
rtime = v[1]
rt_is_def = rtime.Year() <= 1
switch {
case v[0].Year() <= 1:
return false
case v[0].After(now_time):
return false
case (!v[0].Before(rtime) && !rt_is_def):
return false
case !v[0].After(ltime):
return false
// case !rtime.After(ltime):
// return false
// case rtime.After(now_time):
// return false
default:
ltime = v[1]
}
}
return true
}

To check if a time.Time is its zero value, use Time.IsZero().
Other than that, simply implement your rules one-by-one. It won't be the most efficient solution, but it will be clean and simple which you can improve once it works correctly:
func isValid(slarti [][2]time.Time) bool {
now := time.Now()
for i, v := range slarti {
v1, v2 := v[0], v[1]
// Rule #3
if v1.IsZero() {
return false
}
// Rule #1: times must be in the past
if now.Before(v1) || now.Before(v2) {
return false
}
// Rule #2: times can't be the same
if v1.Equal(v2) {
return false
}
if i > 0 && v1.Equal(slarti[i-1][1]) {
return false
}
// Rule #3: invalid entry if no output before:
if i > 0 && slarti[i-1][1].IsZero() {
return false
}
// Rule #4: times must be in ascending order:
if !v2.IsZero() && v2.Before(v1) {
return false
}
if i > 0 && v1.Before(slarti[i-1][1]) {
return false
}
}
return true // Got this far: valid
}
Here's a test code that tests all rules, and also valid inputs (try it on the Go Playground):
cases := []struct {
name string
input [][2]time.Time
valid bool
}{
{
name: "Valid",
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}},
valid: true,
},
{
name: "Valid (2)",
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
valid: true,
},
{
name: "Valid (3)",
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Time{}}},
valid: true,
},
{
name: "Rule #1",
input: [][2]time.Time{{time.Date(2023, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2023, 11, 23, 9, 0, 0, 0, time.UTC)}},
},
{
name: "Rule #2",
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC)}},
},
{
name: "Rule #2 (2)",
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
{
name: "Rule #3",
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Time{}}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
{
name: "Rule #3 (2)",
input: [][2]time.Time{{time.Time{}, time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
{
name: "Rule #4",
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 7, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
}
for i, c := range cases {
if valid := isValid(c.input); valid != c.valid {
log.Printf("[%d] %q expected valid: %t, got: %t", i, c.name, c.valid, valid)
}
}

Related

Logstash Ruby Code to calculate average of array values

For SNMP CPU utilization I am getting data in the below format -
"cpmCPUTotalTable": [
{
"1.1.23": 0,
"1.1.4": 11,
"1.1.10": 12,
"1.1.16": 0,
"1.1.2": 1000,
"1.1.12": 1555064,
"1.1.19": 0,
"1.1.22": 0,
"1.1.14": 221420,
"index": "1000",
"1.1.11": 0,
"1.1.9": 5,
"1.1.21": 0,
"1.1.18": 0,
"1.1.5": 10,
"1.1.15": 1734314400,
"1.1.3": 12,
"1.1.13": 2376240,
"1.1.6": 12,
"1.1.20": 0,
"1.1.17": 0,
"1.1.8": 10,
"1.1.7": 11
},
{
"1.1.23": 0,
"1.1.4": 2,
"1.1.10": 2,
"1.1.16": 0,
"1.1.2": 2000,
"1.1.12": 1537672,
"1.1.19": 0,
"1.1.22": 0,
"1.1.14": 221420,
"index": "2000",
"1.1.11": 0,
"1.1.9": 5,
"1.1.21": 0,
"1.1.18": 0,
"1.1.5": 2,
"1.1.15": 1752823768,
"1.1.3": 2,
"1.1.13": 2393632,
"1.1.6": 2,
"1.1.20": 0,
"1.1.17": 0,
"1.1.8": 2,
"1.1.7": 2
},
{
"1.1.23": 0,
"1.1.4": 2,
"1.1.10": 1,
"1.1.16": 0,
"1.1.2": 3000,
"1.1.12": 1191980,
"1.1.19": 0,
"1.1.22": 0,
"1.1.14": 221420,
"index": "3000",
"1.1.11": 0,
"1.1.9": 5,
"1.1.21": 0,
"1.1.18": 0,
"1.1.5": 1,
"1.1.15": 2013293636,
"1.1.3": 1,
"1.1.13": 2739324,
"1.1.6": 1,
"1.1.20": 0,
"1.1.17": 0,
"1.1.8": 1,
"1.1.7": 2
}
]
Now, I need to calculate the average for values of "1.1.8" in Logstash config using Ruby code. For example here my output should be like - ((10+2+1)/3 = 4.3).
I am very new to logstash and ruby and stuck here. It would be a great help if anyone can give solution or suggestion on the same.
Thanks in advance.
Assuming that all this output is a hash and, for example, is stored in a variable data, the solution could be:
values = data[:cpmCPUTotalTable].map { |data_set| data_set[:"1.1.8"] }
average = values.sum(0.0) / values.count
Or shorter and prettier one-line solution by Cary Swoveland
:
data[:cpmCPUTotalTable].sum { |data_set| data_set[:"1.1.8"] }.fdiv(data[:cpmCPUTotalTable].size)

scss create array 1 to 100 without writing it litteraly

So I have this mixin:
#mixin generateSpacings($prefix, $property) {
$sizes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32];
...
and obviously writing this array like that is ugly and not really maintainable, how could I write it programatically ?
Codepen
I'd go for a solution where I'd generate the array via a #for loop and then append it to a list.
$start: 1;
$end: 100;
$array: "";
// array[1] = "", so $start + 1 to later set `""` to $start
#for $i from $start + 1 through $end {
$array: append($array, $i, comma);
//set `""` to $start
$array: set-nth($array, 1, $start);
}

Loop Issue in Mathematica

I am currently attempting to run a loop in Mathematica which will attempt to insert in position {i,4} of the date list the day of the week. For some reason i can't get dayint to increase when date[[i,3]]!=date[[i-1,3]] and all values of date[[i,4]]=5. I would much appreciate any insight available on this issue.
In[4]:= n = 344674; dayint = 5;
In[5]:= solardata =
Import["U:\\Masters Project\\Hobo \
Data\\SORMS_Landfill_Comparison_Input.csv", "csv"];
In[6]:= date =
Table[DateList[{ToString[solardata[[i, 1]]], {"Month", "Day",
"YearShort"}}], {i, n}];
In[8]:= date[[1, 4]] = 5;
In[14]:= For[i = 2, i < n + 1, i++,
If[date[[i, 3]] == date[[i - 1, 3]], date[[i, 4]] = dayint,
If[dayint == 7, dayint = 1, dayint++]; date[[i, 4]] = dayint]];
In[17]:= date;
Seems to work ok.
n = 3; dayint = 5;
date = {
{2013, 11, 30, 0, 0, 0.},
{2013, 11, 30, 0, 0, 0.},
{2013, 12, 01, 0, 0, 0.}};
For[i = 2, i < n + 1, i++,
If[date[[i, 3]] == date[[i - 1, 3]],
date[[i, 4]] = dayint,
If[dayint == 7, dayint = 1, dayint++];
date[[i, 4]] = dayint]];
date
{{2013, 11, 30, 0, 0, 0.}, {2013, 11, 30, 5, 0, 0.}, {2013, 12, 1, 6,
0, 0.}}
Edit
Perhaps you have missing dates?
date = {
{2013, 11, 28, 0, 0, 0.},
{2013, 11, 29, 0, 0, 0.},
{2013, 11, 29, 0, 0, 0.},
{2013, 11, 30, 0, 0, 0.},
{2013, 11, 30, 0, 0, 0.},
{2013, 12, 01, 0, 0, 0.}};
dates = Union#date;
{mindate, maxdate} = Through[{First, Last}#dates];
days = QuantityMagnitude#DateDifference[mindate, maxdate, "Day"];
If[Length[dates] == days + 1, "All dates included", "There are dates missing"]
All dates included

What's the exact number of compares that it takes insertion sort to compare numbers in this array?

If I have an array A = <0, 15, 5, 1, 0, 20, 25, 30, 35, 40>. When i write the code to count the comparisons, I am confused on where to add a counter, because I'm afraid there might be repeated counts.
Nevertheless, it says there are 15 comparisons. I am not sure this is right. How many comparisons are there really?
int InsertionSort(int A[], int n)
{
int i, j, index, counter = 0;
for (i=1; i < n; i++)
{
index = A[i];
for (j=i-1;j >= 0 && A[j] > index;j--)
{
A[j + 1] = A[j];
counter++;
}
A[j+1] = index;
counter++;
}
return counter;
}
int main()
{
int A[]= {5,4,3,2,1};
int counter = 0;
int n =5;
counter = InsertionSort(A, n);
printf("%d",counter);
return 0;
}
There are 15 comparisons (and 6 swaps):
compare: 0 <= 15, 5, 1, 0, 20, 25, 30, 35, 40
compare: 0, 15 > 5, 1, 0, 20, 25, 30, 35, 40
swap: 0, 5 - 15, 1, 0, 20, 25, 30, 35, 40
compare: 0 <= 5, 15, 1, 0, 20, 25, 30, 35, 40
compare: 0, 5, 15 > 1, 0, 20, 25, 30, 35, 40
swap: 0, 5, 1 - 15, 0, 20, 25, 30, 35, 40
compare: 0, 5 > 1, 15, 0, 20, 25, 30, 35, 40
swap: 0, 1 - 5, 15, 0, 20, 25, 30, 35, 40
compare: 0 <= 1, 5, 15, 0, 20, 25, 30, 35, 40
compare: 0, 1, 5, 15 > 0, 20, 25, 30, 35, 40
swap: 0, 1, 5, 0 - 15, 20, 25, 30, 35, 40
compare: 0, 1, 5 > 0, 15, 20, 25, 30, 35, 40
swap: 0, 1, 0 - 5, 15, 20, 25, 30, 35, 40
compare: 0, 1 > 0, 5, 15, 20, 25, 30, 35, 40
swap: 0, 0 - 1, 5, 15, 20, 25, 30, 35, 40
compare: 0 <= 0, 1, 5, 15, 20, 25, 30, 35, 40
compare: 0, 0, 1, 5, 15 <= 20, 25, 30, 35, 40
compare: 0, 0, 1, 5, 15, 20 <= 25, 30, 35, 40
compare: 0, 0, 1, 5, 15, 20, 25 <= 30, 35, 40
compare: 0, 0, 1, 5, 15, 20, 25, 30 <= 35, 40
compare: 0, 0, 1, 5, 15, 20, 25, 30, 35 <= 40
To me, your counter appears to be on the wrong spot. Let's say A=<3, 2>, then your algorithm would use 1 comparison, but would report counter=2. If 15 is the right answer, then this error did not occur or got canceled out somehow.
To find out if 15 really is the right answer, this is how you can improve the counter. First of all, your algorithm relies on a left-to-right evaluation order of conditions (which most programming language adhere to). What this means is that if P=false then Q is not evaluated in (P && Q). If left-to-right evaluation order is not guaranteed, then the algorithm could potentially evaluate A[-1] > index (something which would crash your program). The easiest way to count correctly is to split the conjunction of the for-loop into two separate lines as follows:
for (i=1; i < n; i++)
{
index = A[i];
for (j=i-1; j >= 0; j--)
{
// Every time this line is reached, a comparison will be performed
counter++;
if (A[j] > index)
{
A[j + 1] = A[j];
}
}
A[j+1] = index;
}
If this works out, please let us know the result and please up-vote this answer.

Select Range of SQLDateTimes

table = {{ID1, SQLDateTime[{1978, 1, 10, 0, 0, 0.`}]},
{ID2, SQLDateTime[{1999, 1, 10, 0, 0, 0.`}]},
{ID3, SQLDateTime[{2010, 9, 10, 0, 0, 0.`}]},
{ID4, SQLDateTime[{2011, 1, 10, 0, 0, 0.`}]}}
I'd like to return all cases in table in which the SQLDateTime is within the last year (DatePlus[{-1, "Year"}]). How do I specify a search for those cases?
You could also use DateDifference:
Cases[table, {a_, SQLDateTime[b_]} /;
DateDifference[b, DateList[], "Year"][[1]] <= 1]
Select[table, (AbsoluteTime[ DatePlus[{-1, "Year"}]] <=
AbsoluteTime[ #[[2, 1]]] <= AbsoluteTime[ ] &)]
(* ==> {{ID3, SQLDateTime[{2010, 9, 10, 0, 0, 0.}]},
{ID4,SQLDateTime[{2011, 1, 10, 0, 0, 0.}]}
}
*)
Small update (pre-caching of Date[], based on Leonid's comments):
With[
{date = Date[]},
Select[table,
(AbsoluteTime[ DatePlus[date, {-1, "Year"}]] <=
AbsoluteTime[ #[[2, 1]]] <= AbsoluteTime[date ] &)]
]
This also removes a problem with the original DatePlus[{-1, "Year"}] which only takes today's date into account and not the current time.

Resources