-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathusing_channels_arithmetic_progression.go
More file actions
132 lines (93 loc) · 3.3 KB
/
Copy pathusing_channels_arithmetic_progression.go
File metadata and controls
132 lines (93 loc) · 3.3 KB
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Using channels
// :PROPERTIES:
// :header-args:go+: :eval no
// :header-args:go+: :tangle using_channels_arithmetic_progression.go
// :header-args:go+: :package 'discard
// :END:
// Ok, so hear me out, the above works just fine of course, but in other languages I would be using a generator or a stream to calculate the stream of deltas which I could then just compare one after the other, perhaps even generating another generator. With Go, the equivalent is to use channels. [[https://stackoverflow.com/a/34466755/5056][Because of the semantics around closing them]] hover it's not so straightforward and has higher overhead. Still, I would like to try and implement it as a learning exercise.
// First some standard imports
// #+name: implementation/set-up
// [[file:README.org::implementation/set-up][implementation/set-up]]
package main
import (
"fmt"
"slices"
)
var _ = fmt.Printf // Just for the sake of how we're structuring things here we don't want to get an unused import error
// implementation/set-up ends here
// Here there will actually be multiple channels
// - *Channel that has written into it a sorted stream of numbers*
// #+name: implementation/emitSequentialNumbers
// [[file:README.org::implementation/emitSequentialNumbers][implementation/emitSequentialNumbers]]
func emitSequentialNumbers(array []int) <-chan int {
c := make(chan int)
go func() {
defer close(c)
sortedArray := slices.Clone(array)
slices.Sort(sortedArray)
for _, num := range sortedArray {
c <- num
}
}()
return c
}
// implementation/emitSequentialNumbers ends here
// #+RESULTS:
// : -2
// : 1
// : 3
// : 5
// Sweet!
// --------
// - **Channel that has written into it deltas between sequential numbers**
// #+name: implementation/emitDeltasBetweenSequentialNumbers
// [[file:README.org::*Using channels][Using channels:4]]
func emitDeltasBetweenSequentialNumbers(sequentialNumbers <-chan int) <-chan int {
c:= make(chan int)
go func() {
defer close(c)
if prevItem, ok := <- sequentialNumbers; ok {
for newItem := range sequentialNumbers {
c <- (newItem - prevItem)
prevItem = newItem
}
}
}()
return c
}
// Using channels:4 ends here
// #+RESULTS:
// : 3
// : 2
// : 2
// That is indeed correct
// --------
// - **Signal-only channel that has written into it a signal which pops whether two sequential numbers have changed**
// #+name: implementation/emitIfValueChanged
// [[file:README.org::implementation/emitIfValueChanged][implementation/emitIfValueChanged]]
func emitIfValueChanged[T comparable](values <-chan T) <-chan struct{} {
c:= make(chan struct{})
go func() {
defer close(c)
if firstItem, ok := <- values; ok {
for newItem := range values {
if(newItem != firstItem) {
c <- struct{}{}
}
}
}
}()
return c
}
// implementation/emitIfValueChanged ends here
// #+RESULTS:
// : got a change in the second loop
// Aha, interesting how the ~_~ variable was not only not necessary here, but actually didn't work
// ------
// Finally, lets actually create a function to return true/false here
// [[file:README.org::*Using channels][Using channels:8]]
func IsArithmeticProgressionWithChannels(array []int) bool {
_, changed := <-emitIfValueChanged(emitDeltasBetweenSequentialNumbers(emitSequentialNumbers(array)))
return !changed
}
// Using channels:8 ends here