Last active
February 8, 2020 20:09
-
-
Save kamermans/0f91f2a0fc955845b3d2aa28a4253949 to your computer and use it in GitHub Desktop.
Compute date palindromes efficiently
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"os" | |
"sort" | |
"sync" | |
"time" | |
) | |
const ( | |
start = 2020 | |
end = 2030 | |
show = 50 | |
) | |
func init() { | |
os.Setenv("TZ", "UTC") | |
} | |
func main() { | |
var wg sync.WaitGroup | |
palindromes := make(chan Palindrome) | |
timing := time.Now() | |
initSearch(start, end) | |
searches := []SearchFunc{ | |
searchByDay, | |
searchBySecond, | |
searchTimestamp, | |
} | |
// Run all the searches in parallel | |
for _, search := range searches { | |
search := search | |
wg.Add(1) | |
go func() { | |
defer wg.Done() | |
search(start, end, palindromes) | |
}() | |
} | |
// Close channel after all searches are finished | |
go func() { | |
wg.Wait() | |
close(palindromes) | |
}() | |
// Sort results | |
results := []Palindrome{} | |
for palindrome := range palindromes { | |
results = append(results, palindrome) | |
} | |
sort.Slice(results, func(i, j int) bool { | |
return results[i].ToTime().Before(results[j].ToTime()) | |
}) | |
// Print results | |
for i, palindrome := range results { | |
if i < show { | |
fmt.Printf("%v\n", palindrome) | |
} | |
} | |
fmt.Printf("Found %v palindromes in %v\n", len(results), time.Since(timing)) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ go build . && ./Palindrome.exe | |
2020-01-01 09:09:11 (Timestamp: 1577887751) | |
2020-01-02 15:42:31 (Timestamp: 1577997751) | |
2020-01-02 18:45:51 (Timestamp: 1578008751) | |
2020-01-04 01:19:11 (Timestamp: 1578118751) | |
2020-01-05 07:52:31 (Timestamp: 1578228751) | |
2020-01-06 14:25:51 (Timestamp: 1578338751) | |
2020-01-07 20:59:11 (Timestamp: 1578448751) | |
2020-01-09 03:32:31 (Timestamp: 1578558751) | |
2020-01-10 10:05:51 (Timestamp: 1578668751) | |
2020-01-11 10:02:02 (Date/Time: 20200111100202) | |
2020-01-11 16:39:11 (Timestamp: 1578778751) | |
2020-01-12 23:12:31 (Timestamp: 1578888751) | |
2020-01-14 05:45:51 (Timestamp: 1578998751) | |
2020-01-14 08:49:11 (Timestamp: 1579009751) | |
2020-01-15 15:22:31 (Timestamp: 1579119751) | |
2020-01-16 21:55:51 (Timestamp: 1579229751) | |
2020-01-18 04:29:11 (Timestamp: 1579339751) | |
2020-01-19 11:02:31 (Timestamp: 1579449751) | |
2020-01-20 17:35:51 (Timestamp: 1579559751) | |
2020-01-22 00:09:11 (Timestamp: 1579669751) | |
2020-01-22 10:02:02 (Date/Time: 20200122100202) | |
2020-01-23 06:42:31 (Timestamp: 1579779751) | |
2020-01-24 13:15:51 (Timestamp: 1579889751) | |
2020-01-25 19:49:11 (Timestamp: 1579999751) | |
2020-01-25 20:07:31 (Timestamp: 1580000851) | |
2020-01-27 02:40:51 (Timestamp: 1580110851) | |
2020-01-28 09:14:11 (Timestamp: 1580220851) | |
2020-01-29 15:47:31 (Timestamp: 1580330851) | |
2020-01-30 22:20:51 (Timestamp: 1580440851) | |
2020-02-01 04:54:11 (Timestamp: 1580550851) | |
2020-02-02 (Date: 20200202) | |
2020-02-02 11:27:31 (Timestamp: 1580660851) | |
2020-02-03 18:00:51 (Timestamp: 1580770851) | |
2020-02-05 00:34:11 (Timestamp: 1580880851) | |
2020-02-06 07:07:31 (Timestamp: 1580990851) | |
2020-02-06 10:10:51 (Timestamp: 1581001851) | |
2020-02-07 16:44:11 (Timestamp: 1581111851) | |
2020-02-08 23:17:31 (Timestamp: 1581221851) | |
2020-02-10 05:50:51 (Timestamp: 1581331851) | |
2020-02-11 12:24:11 (Timestamp: 1581441851) | |
2020-02-11 20:02:02 (Date/Time: 20200211200202) | |
2020-02-12 18:57:31 (Timestamp: 1581551851) | |
2020-02-14 01:30:51 (Timestamp: 1581661851) | |
2020-02-15 08:04:11 (Timestamp: 1581771851) | |
2020-02-16 14:37:31 (Timestamp: 1581881851) | |
2020-02-17 21:10:51 (Timestamp: 1581991851) | |
2020-02-18 00:14:11 (Timestamp: 1582002851) | |
2020-02-19 06:47:31 (Timestamp: 1582112851) | |
2020-02-20 13:20:51 (Timestamp: 1582222851) | |
2020-02-21 19:54:11 (Timestamp: 1582332851) | |
Found 3544 palindromes in 2.9637ms |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"strconv" | |
"time" | |
) | |
var ( | |
monthDays = []int{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} | |
bySecondMonthHourCombos = map[int]int{} | |
bySecondYearTimeCombos = map[int][2]int{} | |
bySecondDays = []int{11, 22} | |
bySecondLength = 14 | |
) | |
type Palindrome interface { | |
ToInt() int | |
ToTime() time.Time | |
String() string | |
} | |
type SearchFunc = func(int, int, chan<- Palindrome) | |
type SecondPalindrome struct { | |
Year, Month, Day, Hour, Minute, Second int | |
intVal int | |
} | |
func (p *SecondPalindrome) ToInt() int { | |
if p.intVal == 0 { | |
p.intVal = makeDateBySecond(p.Year, p.Month, p.Day, p.Hour, p.Minute, p.Second) | |
} | |
return p.intVal | |
} | |
func (p SecondPalindrome) ToTime() time.Time { | |
return time.Date(p.Year, time.Month(p.Month), p.Day, p.Hour, p.Minute, p.Second, 0, time.UTC) | |
} | |
func (p SecondPalindrome) String() string { | |
return p.ToTime().Format("2006-01-02 15:04:05") + " (Date/Time: " + strconv.Itoa(p.ToInt()) + ")" | |
} | |
type DayPalindrome struct { | |
Year, Month, Day int | |
intVal int | |
} | |
func (p *DayPalindrome) ToInt() int { | |
if p.intVal == 0 { | |
p.intVal = makeDateByDay(p.Year, p.Month, p.Day) | |
} | |
return p.intVal | |
} | |
func (p DayPalindrome) ToTime() time.Time { | |
return time.Date(p.Year, time.Month(p.Month), p.Day, 0, 0, 0, 0, time.UTC) | |
} | |
func (p DayPalindrome) String() string { | |
return p.ToTime().Format("2006-01-02") + " (Date: " + strconv.Itoa(p.ToInt()) + ")" | |
} | |
type TimestampPalindrome struct { | |
Val int | |
} | |
func (p *TimestampPalindrome) ToInt() int { | |
return p.Val | |
} | |
func (p TimestampPalindrome) ToTime() time.Time { | |
return time.Unix(int64(p.Val), 0) | |
} | |
func (p TimestampPalindrome) String() string { | |
return p.ToTime().Format("2006-01-02 15:04:05") + " (Timestamp: " + strconv.Itoa(p.Val) + ")" | |
} | |
func initSearch(start, end int) { | |
// YY YY MM D D HH MM SS | |
// MM == rev(HH) | |
// YYYY = rev(MM SS) | |
for month := 1; month < 13; month++ { | |
hour := reverseInt(month, 2) | |
if hour > 23 { | |
continue | |
} | |
bySecondMonthHourCombos[month] = reverseInt(month, 2) | |
} | |
} | |
func makeDateBySecond(year, month, day, hour, minute, second int) int { | |
return year*10000000000 + month*100000000 + day*1000000 + hour*10000 + minute*100 + second | |
} | |
func makeDateByDay(year, month, day int) int { | |
return year*10000 + month*100 + day | |
} | |
func searchBySecond(start, end int, palindromes chan<- Palindrome) { | |
for year := start; year <= end; year++ { | |
minuteSecond := reverseInt(year, 4) | |
minute := minuteSecond / 100 | |
second := minuteSecond % 100 | |
if minute > 59 || second > 59 || second == 0 || second%10 == 0 { | |
continue | |
} | |
for month, hour := range bySecondMonthHourCombos { | |
for _, day := range bySecondDays { | |
palindromes <- &SecondPalindrome{year, month, day, hour, minute, second, 0} | |
} | |
} | |
} | |
} | |
func searchByDay(start, end int, palindromes chan<- Palindrome) { | |
for year := start; year <= end; year++ { | |
monthDay := reverseInt(year, 4) | |
month := monthDay / 100 | |
day := monthDay % 100 | |
if month > 12 || day > daysIn(month, year) || day%10 == 0 { | |
continue | |
} | |
palindromes <- &DayPalindrome{year, month, day, 0} | |
} | |
} | |
func searchTimestamp(start, end int, palindromes chan<- Palindrome) { | |
startTS := int(time.Date(start, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()) | |
endTS := int(time.Date(end, time.December, 31, 23, 59, 59, 0, time.UTC).Unix()) | |
// 1581190424 | |
startTSPrefix := startTS / 100000 | |
endTSPrefix := endTS / 100000 | |
for prefix := startTSPrefix; prefix <= endTSPrefix; prefix++ { | |
ts := prefix*100000 + reverseInt(prefix, 5) | |
if ts < startTS || ts > endTS { | |
continue | |
} | |
palindromes <- &TimestampPalindrome{ts} | |
} | |
} | |
func isPalindromeRune(d []rune) bool { | |
for i := 0; i < len(d)/2; i++ { | |
if d[i] != d[len(d)-1-i] { | |
return false | |
} | |
} | |
return true | |
} | |
func isPalindrome(num, length int) bool { | |
return isPalindromeRune([]rune(strconv.Itoa(reverseInt(num, length)))) | |
} | |
func daysIn(m int, year int) int { | |
if m == 2 && isLeap(year) { | |
return 29 | |
} | |
return monthDays[m] | |
} | |
func isLeap(year int) bool { | |
return year%4 == 0 && (year%100 != 0 || year%400 == 0) | |
} | |
func reverseInt(n, length int) int { | |
r := 0 | |
// for n != 0 { | |
for i := 0; i < length; i++ { | |
r = r * 10 | |
r = r + n%10 | |
n = n / 10 | |
} | |
return r | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment