Hash table in Racket - sorting

I'm new to Racket and I'm trying to define a function sort-mail that is gonna sort a hash table.
I've some defined lists:
(define test-dates
'("Sun, 10 Sep 2017 09:48:44 +0200"
"Wed, 13 Sep 2017 17:51:05 +0000"
"Sun, 10 Sep 2017 13:16:19 +0200"
"Tue, 17 Nov 2009 18:21:38 -0500"
"Wed, 13 Sep 2017 10:40:47 -0700"
"Thu, 14 Sep 2017 12:03:35 -0700"
"Wed, 18 Nov 2009 02:22:12 -0800"
"Sat, 09 Sep 2017 13:40:18 -0700"
"Tue, 26 Oct 2010 15:11:06 +0200"
"Tue, 17 Nov 2009 18:04:31 -0800"
"Mon, 17 Oct 2011 04:15:12 +0000"
"Sun, 16 Oct 2011 23:12:02 -0500"
"Mon, 11 Sep 2017 14:41:12 +0100"))
(define sorted-dates
'("Tue, 17 Nov 2009 18:04:31 -0800"
"Tue, 17 Nov 2009 18:21:38 -0500"
"Wed, 18 Nov 2009 02:22:12 -0800"
"Tue, 26 Oct 2010 15:11:06 +0200"
"Sun, 16 Oct 2011 23:12:02 -0500"
"Mon, 17 Oct 2011 04:15:12 +0000"
"Sat, 09 Sep 2017 13:40:18 -0700"
"Sun, 10 Sep 2017 09:48:44 +0200"
"Sun, 10 Sep 2017 13:16:19 +0200"
"Mon, 11 Sep 2017 14:41:12 +0100"
"Wed, 13 Sep 2017 10:40:47 -0700"
"Wed, 13 Sep 2017 17:51:05 +0000"
"Thu, 14 Sep 2017 12:03:35 -0700"))
The function is supposed to pass this test.
(module+ test
(define test-hashes (map (lambda (x) (hasheq 'Date x)) test-dates))
(define sorted-hashes (map (lambda (x) (hasheq 'Date x)) sorted-dates))
(check-equal? (sort-mail test-hashes) sorted-hashes))
So, how do I even start? I find hash tables in Racket very difficult. I thought of using the sort function, but it guess it doesn't take a hash table as an argument.

Hash tables are inherently sorted. By design, they allow for (theoretically) instant lookup time by mapping a unique key to an index. So, there is no sorting mechanism to act on a hash-map as there is no need. If you are trying to aggregate the key value pairs into a list, and then sort, that is certainly possible.
hash-keys will return a list of keys in the table.
hash-values will return a list of values in the table.
These lists can be sorted. You can also pair each element of each list together, (so a list of key-value pairs). Try the following:
(define h (make-immutable-hash
(list (cons 1 2)
(cons 3 4)
(cons 5 6)
(cons 7 8))))
(define (pair-up key value)
(list key value))
(map pair-up (hash-keys h) (hash-values h))
; Alternative to above, where pair-up is essentially defined inside.
(map (lambda (key value) (list key value)) (hash-keys h) (hash-values h))

Related

Dividing within a column based on other columns matching

I am trying to calculate the current measurement in column “Total" minus the lowest measurement previously recorded in column "Total" where the current measurement in column “Total” corresponding to the value in column "Trade" is less than(<) the minimum measurement in column “Total” corresponding to the value in column "trade", and if two values in the “SUBJECT” column match and two values in the “PROCEDURE” column match. To emphasize, the minimum value must be a previously recorded. If the measurement is less than the current measurement but was not recorded previously (according to the “date” column), it does not quality to be subtracted from the current measurement. An example of the output is provided below.
data Have;
input Subject Type :$12. Date &:anydtdte. Trade Procedure :$12. Measurement;
format date yymmdd10.;
datalines;
Subject Type Date Trade Procedure Total
500 Initial 15 AUG 2017 6 Invasive 20
500 Initial 15 AUG 2017 9 Surface 35
500 Followup 15 AUG 2018 8 Invasive 54
428 Followup 15 AUG 2018 56 Outer 29
765 Seventh 3 AUG 2018 12 Other 13
500 Followup 3 JUL 2018 23 surface 98
428 Initial 3 JUL 2017 34 Outer 10
765 Initial 20 JUL 2019 4 Other 19
610 Third 20 AUG 2019 58 Invasive 66
610 Initial 17 Mar 2018 25 Invasive 17
*Example of Output;
Subject Type Date Trade Procedure Total Output
500 Initial 15 AUG 2017 6 Invasive 20 20/20
500 Initial 15 AUG 2017 9 Surface 35 35/35
500 Followup 15 AUG 2018 8 Invasive 54 54/20
428 Followup 15 AUG 2018 56 Outer 29 29/10
765 Seventh 3 AUG 2018 12 Other 13 13/19
500 Followup 3 JUL 2018 23 surface 98 98/35
428 Initial 3 JUL 2017 34 Outer 10 10/10
765 Initial 20 JUL 2019 4 Other 19 19/19
610 Third 20 AUG 2019 58 Invasive 66 66/17
610 Initial 17 Mar 2018 25 Invasive 17 17/17
not sure, but this is the closest thing i could get to match your output
I made a monotonic() variable, and then ranked it by SUBJECT and PROCEDURE variables. and then joined the table to itself using condition t1.rank_monotonic +1 = t2.rank_monotonic.

Building a mask out of a selection of days of week (MTWTFSS) to find whether a specific day matches via basic operators only

Given a selection of days of week, I need to know whether a specific day is matching the selection.
For example, given:
enum DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN
}
And the following selection:
List<DayOfWeek> selection = List.of(MON, WED);
If a given day's day of week is MON or WED, then it should match, otherwise it shouldn't.
A straightforward approach:
boolean match = selection.contains(day.getDayOfWeek());
I'm wondering whether there's a way to build a mask out of the selection, and finding whether a given day matches only with basic operators (+ - * / % AND OR NOT EQ LT LTE GT GTE, no bitwise operators allowed).
For instance, given that same selection:
int mask = 1010000; // just an example of a mask, can be any other
Then:
boolean match = fn(mask, day.getDayOfWeek());
Could such a mask exist so that fn can be written with basic operators only?
Instead of a boolean approach, take some prime numbers
MON, TUE, WED, THU, FRI, SAT, SUN
2, 3, 5, 7, 11, 13, 17
The mask is composed of the product of selected day, e.g (MON, WED) -> 2*5 = 10
The dayOfWeek matches iff it divides the mask (idem mask % dayOfWeek === 0)
e.g
TUE -> 3, mask % 3 != 0, not in selection
MON -> 2, mask % 2 === 0, in selection

Calculating which day of the week a date falls on using Gauss's algorithm, ordinal date and modulo arithmetic

After calculating which day of the week the 1st of January falls on using Gauss's algorithm, as well as calculating the ordinal date for a given calendar date, how can the day of the week of the latter date be calculated?
For example, Gauss's algorithm can tell us that, this year, the 1st of January fell on a Sunday, the 7th day of the week. Today is the 22nd of October, with an ordinal day of 295. How can this information be used to calculate that today is a Sunday?
For common years (= non-leap years), 1st of January and 1st of October are on the same day of the week:
Jan 31
Feb 28
Mar 31
Apr 30
May 31
Jun 30
Jul 31
Aug 30
Sep 31
Sum 273 = 39 x 7
See Wikipedia
22nd October is exactly three weeks later than 1st of October.
An approach I've found, which I haven't tested extensively, but seems to work with the dates I've thrown at it, is...
(ordinal day + day of 1st of January - 1) % 7
Where Mon = 1, Tue = 2,..., Sat = 6, Sun = 0.
In the example mentioned in the question:
(295 + 0 - 1) % 7 = 0 (Sunday)

What is the significance of Go's time.Format(layout string) reference time?

What is the significance of Go's time.Format(layout string) reference time, ie:
Mon Jan 2 15:04:05 -0700 MST 2006
This specific time couldn't have been chosen completely randomly, right?
Source: http://golang.org/pkg/time/#Time.Format
Each part of the date is used as an index:
Jan -> 1 -> Month
2 -> 2 -> Day-of-Month
15 = 3PM -> 15/3 -> hour
04 -> 4 -> minute
05 -> 5 -> second
2006 -> 6 -> year
-0700 -> 7 -> time-zone
So according to the doc:
Since MST is GMT-0700, the reference time can be thought of as
01/02 03:04:05PM '06 -0700
This makes it easy for the time.Format method to parse human-readable date format specifications that are visually identical to the desired result.
Compare this to for example the strftime C function that uses hard-to-remember format strings such as "%a, %d %b %y %T %z" which represents a RFC 822-compliant date format.
The Go equivalent is: "Mon, 02 Jan 06 15:04 MST".
The time.Format will tokenize this string and analyze each word.
Mon is recognized litteraly as monday so this is the week day's name
the comma is left untouched
02 is recognized as the integer value 2, representing a day-of-month in the index
Jan is the known english abbreviation for the january month, so this is used for the month part
06 is 6 so this the year part
15 is equivalent to 3 and represent the hour
the ':' character is left untouched
04 is 4, therefore the minute
MST is interpreted litteraly
See https://github.com/golang/go/blob/go1.15/src/time/format.go#L151 for the exact algorithm.
In American date format, it's Mon, 1/2 03:04:05 PM 2006 -0700.
1, 2, 3, 4, 5, 6, 7.

How to get middle period of 2 date periods in ruby?

c should be inner period of 2 periods. How to get it in most elegant way?
a1=Date.current
a2=Date.current + 2.months
b1=Date.current + 1.month
b2=Date.current + 3.months
c=???
c.should_be [Date.current + 1.month, Date.current + 2.months]
Hurried implementation:
xs = (a1..a2).to_a & (b1..b2).to_a
(xs.first..xs.last)
# => Sun, 24 Jun 2012..Tue, 24 Jul 2012
There is nothing special about a range of dates. So search "range intersection" to do it more efficiently (for example here). Now you can write:
(a1..a2) & (b1..b2)
d= [a1, a2, b1, b2]
[*1..d.length/ 2].map do |dt|
d.shift(2)
end.map do |dx|
Date.current+ (dx[1]- dx[0])
end
[Sun, 24 Jun 2012, Tue, 24 Jul 2012]

Resources