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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
<head>
<link href="../favicon.ico" rel="shortcut icon" type="image/x-icon"/>
<link href="../style.css" rel="stylesheet"/>
<title>BQN: Self-search functions</title>
</head>
<div class="nav">(<a href="https://github.com/mlochbaum/BQN">github</a>) / <a href="../index.html">BQN</a> / <a href="index.html">doc</a></div>
<h1 id="self-search-functions"><a class="header" href="#self-search-functions">Self-search functions</a></h1>
<svg viewBox='-115.2 -33 676.8 299.2'>
<defs>
<mask id='m'>
<rect fill='white' x='-76.8' y='-24.2' width='600' height='281.6'/>
<g fill='black'>
<rect x='-7' y='-7.8' width='14' height='20'/>
<rect x='41' y='-7.8' width='14' height='20'/>
<rect x='89' y='-7.8' width='14' height='20'/>
<rect x='137' y='-7.8' width='14' height='20'/>
<rect x='185' y='-7.8' width='14' height='20'/>
<rect x='233' y='-7.8' width='14' height='20'/>
<rect x='281' y='-7.8' width='14' height='20'/>
<rect x='329' y='-7.8' width='14' height='20'/>
<rect x='377' y='-7.8' width='14' height='20'/>
<rect x='425' y='-7.8' width='14' height='20'/>
<rect x='473' y='-7.8' width='14' height='20'/>
<rect x='-7' y='29.6' width='14' height='20'/>
<rect x='41' y='29.6' width='14' height='20'/>
<rect x='89' y='29.6' width='14' height='20'/>
<rect x='137' y='29.6' width='14' height='20'/>
<rect x='185' y='29.6' width='14' height='20'/>
<rect x='233' y='29.6' width='14' height='20'/>
<rect x='281' y='29.6' width='14' height='20'/>
<rect x='329' y='29.6' width='14' height='20'/>
<rect x='377' y='29.6' width='14' height='20'/>
<rect x='425' y='29.6' width='14' height='20'/>
<rect x='473' y='29.6' width='14' height='20'/>
<rect x='-7' y='64.8' width='14' height='20'/>
<rect x='41' y='86.8' width='14' height='20'/>
<rect x='89' y='108.8' width='14' height='20'/>
<rect x='137' y='108.8' width='14' height='20'/>
<rect x='185' y='86.8' width='14' height='20'/>
<rect x='233' y='108.8' width='14' height='20'/>
<rect x='281' y='108.8' width='14' height='20'/>
<rect x='329' y='86.8' width='14' height='20'/>
<rect x='377' y='130.8' width='14' height='20'/>
<rect x='425' y='130.8' width='14' height='20'/>
<rect x='473' y='86.8' width='14' height='20'/>
<rect x='-7' y='166' width='14' height='20'/>
<rect x='41' y='166' width='14' height='20'/>
<rect x='89' y='166' width='14' height='20'/>
<rect x='137' y='166' width='14' height='20'/>
<rect x='185' y='166' width='14' height='20'/>
<rect x='233' y='166' width='14' height='20'/>
<rect x='281' y='166' width='14' height='20'/>
<rect x='329' y='166' width='14' height='20'/>
<rect x='377' y='166' width='14' height='20'/>
<rect x='425' y='166' width='14' height='20'/>
<rect x='473' y='166' width='14' height='20'/>
<rect x='-7' y='218.8' width='14' height='20'/>
<rect x='41' y='218.8' width='14' height='20'/>
<rect x='89' y='218.8' width='14' height='20'/>
<rect x='137' y='218.8' width='14' height='20'/>
</g>
</mask>
</defs>
<g font-family='BQN,monospace' font-size='18px' text-anchor='middle'>
<rect class='code' stroke-width='1.5' rx='12' x='-76.8' y='-24.2' width='600' height='281.6'/>
<g class='purple' stroke-width='0' opacity='0.5'>
<rect x='-67.2' y='24.2' width='580.8' height='30.8'/>
<rect x='-67.2' y='160.6' width='580.8' height='30.8'/>
</g>
<g stroke-width='0.5' stroke='currentColor' fill='none' mask='url(#m)'>
<path d='M0 0V182.6L0 217.8M0 74.8H499.2'/>
<path d='M48 0V182.6L48 217.8M48 96.8H499.2'/>
<path d='M96 0V182.6L96 217.8M96 118.8H499.2'/>
<path d='M384 0V182.6L144 217.8M384 140.8H499.2'/>
</g>
<text dy='0.32em' x='0' y='0'><tspan class='String'>'m'</tspan></text>
<text dy='0.32em' x='48' y='0'><tspan class='String'>'i'</tspan></text>
<text dy='0.32em' x='96' y='0'><tspan class='String'>'s'</tspan></text>
<text dy='0.32em' x='144' y='0'><tspan class='String'>'s'</tspan></text>
<text dy='0.32em' x='192' y='0'><tspan class='String'>'i'</tspan></text>
<text dy='0.32em' x='240' y='0'><tspan class='String'>'s'</tspan></text>
<text dy='0.32em' x='288' y='0'><tspan class='String'>'s'</tspan></text>
<text dy='0.32em' x='336' y='0'><tspan class='String'>'i'</tspan></text>
<text dy='0.32em' x='384' y='0'><tspan class='String'>'p'</tspan></text>
<text dy='0.32em' x='432' y='0'><tspan class='String'>'p'</tspan></text>
<text dy='0.32em' x='480' y='0'><tspan class='String'>'i'</tspan></text>
<text dy='0.32em' x='0' y='39.6'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='48' y='39.6'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='96' y='39.6'><tspan class='Number'>2</tspan></text>
<text dy='0.32em' x='144' y='39.6'><tspan class='Number'>2</tspan></text>
<text dy='0.32em' x='192' y='39.6'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='240' y='39.6'><tspan class='Number'>2</tspan></text>
<text dy='0.32em' x='288' y='39.6'><tspan class='Number'>2</tspan></text>
<text dy='0.32em' x='336' y='39.6'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='384' y='39.6'><tspan class='Number'>3</tspan></text>
<text dy='0.32em' x='432' y='39.6'><tspan class='Number'>3</tspan></text>
<text dy='0.32em' x='480' y='39.6'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='0' y='74.8'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='48' y='96.8'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='96' y='118.8'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='144' y='118.8'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='192' y='96.8'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='240' y='118.8'><tspan class='Number'>2</tspan></text>
<text dy='0.32em' x='288' y='118.8'><tspan class='Number'>3</tspan></text>
<text dy='0.32em' x='336' y='96.8'><tspan class='Number'>2</tspan></text>
<text dy='0.32em' x='384' y='140.8'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='432' y='140.8'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='480' y='96.8'><tspan class='Number'>3</tspan></text>
<text dy='0.32em' x='0' y='176'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='48' y='176'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='96' y='176'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='144' y='176'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='192' y='176'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='240' y='176'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='288' y='176'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='336' y='176'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='384' y='176'><tspan class='Number'>1</tspan></text>
<text dy='0.32em' x='432' y='176'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='480' y='176'><tspan class='Number'>0</tspan></text>
<text dy='0.32em' x='0' y='228.8'><tspan class='String'>'m'</tspan></text>
<text dy='0.32em' x='48' y='228.8'><tspan class='String'>'i'</tspan></text>
<text dy='0.32em' x='96' y='228.8'><tspan class='String'>'s'</tspan></text>
<text dy='0.32em' x='144' y='228.8'><tspan class='String'>'p'</tspan></text>
<g font-size='24px'>
<text dy='0.32em' x='-50.4' y='-1.1'><tspan class='Value'>𝕩</tspan></text>
<text dy='0.32em' x='-50.4' y='38.5'><tspan class='Function'>⊐</tspan></text>
<text dy='0.32em' x='-50.4' y='106.7'><tspan class='Function'>⊒</tspan></text>
<text dy='0.32em' x='-50.4' y='174.9'><tspan class='Function'>∊</tspan></text>
<text dy='0.32em' x='-50.4' y='227.7'><tspan class='Function'>⍷</tspan></text>
</g>
</g>
</svg>
<p>BQN has four self-search functions, Classify (<code><span class='Function'>⊐</span></code>), Occurrence Count (<code><span class='Function'>⊒</span></code>), Mark Firsts (<code><span class='Function'>∊</span></code>), and Deduplicate (<code><span class='Function'>⍷</span></code>). Each of these is a monadic function that obtains its result by comparing each <a href="array.html#cells">major cell</a> of the argument (which must have rank at least 1) to the earlier major cells with <a href="match.html">match</a>. For example, Mark Firsts indicates the cells that don't match any earlier cell, which might be called the first of their kind.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oiKICJhYmFhY2Ii">↗️</a><pre> <span class='Function'>∊</span> <span class='String'>"abaacb"</span>
⟨ 1 1 0 0 1 0 ⟩
</pre>
<p>When the argument is a list, its major cells are units and thus contain one element each, so it's just as valid to say that a self-search function compares elements of its argument. Only with a higher-rank argument does the major cell nature become apparent.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGFyciDihpAgPiJhYmMi4oC/ImRjYiLigL8iYWJjIuKAvyJiY2Qi4oC/ImRjYiIK4oiKIGFycg==">↗️</a><pre> <span class='Function'>⊢</span> <span class='Value'>arr</span> <span class='Gets'>←</span> <span class='Function'>></span><span class='String'>"abc"</span><span class='Ligature'>‿</span><span class='String'>"dcb"</span><span class='Ligature'>‿</span><span class='String'>"abc"</span><span class='Ligature'>‿</span><span class='String'>"bcd"</span><span class='Ligature'>‿</span><span class='String'>"dcb"</span>
┌─
╵"abc
dcb
abc
bcd
dcb"
┘
<span class='Function'>∊</span> <span class='Value'>arr</span>
⟨ 1 1 0 1 0 ⟩
</pre>
<p>The result has one number for each major cell, or in other words is a list with the same length as its argument. Three self-search functions follow this pattern, but Deduplicate (<code><span class='Function'>⍷</span></code>) is different: it returns an array of the same rank but possibly a shorter length than the argument.</p>
<h3 id="deduplicate"><a class="header" href="#deduplicate">Deduplicate</a></h3>
<p>Deduplicate removes every major cell from the argument that matches an earlier cell, resulting in an array with the same rank but possibly a shorter length. It might also be described as returning the unique major cells of the argument, ordered by first occurrence. Deduplicate <a href="under.html">Under</a> <a href="reverse.html">Reverse</a> (<code><span class='Function'>⍷</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>) orders by last occurrence instead.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4o23ID4idGFrZSLigL8iZHJvcCLigL8iZHJvcCLigL8icGljayLigL8idGFrZSLigL8idGFrZSIKCuKNt+KMvuKMvSA+InRha2Ui4oC/ImRyb3Ai4oC/ImRyb3Ai4oC/InBpY2si4oC/InRha2Ui4oC/InRha2Ui">↗️</a><pre> <span class='Function'>⍷</span> <span class='Function'>></span><span class='String'>"take"</span><span class='Ligature'>‿</span><span class='String'>"drop"</span><span class='Ligature'>‿</span><span class='String'>"drop"</span><span class='Ligature'>‿</span><span class='String'>"pick"</span><span class='Ligature'>‿</span><span class='String'>"take"</span><span class='Ligature'>‿</span><span class='String'>"take"</span>
┌─
╵"take
drop
pick"
┘
<span class='Function'>⍷</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span> <span class='Function'>></span><span class='String'>"take"</span><span class='Ligature'>‿</span><span class='String'>"drop"</span><span class='Ligature'>‿</span><span class='String'>"drop"</span><span class='Ligature'>‿</span><span class='String'>"pick"</span><span class='Ligature'>‿</span><span class='String'>"take"</span><span class='Ligature'>‿</span><span class='String'>"take"</span>
┌─
╵"drop
pick
take"
┘
</pre>
<h2 id="classify"><a class="header" href="#classify">Classify</a></h2>
<p>Classify is the universal self-search function, in that it preserves all the self-search information in its argument. It gives each different cell value a natural number, ordered by first appearance.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqQIDXigL824oC/MuKAvzLigL814oC/MQ==">↗️</a><pre> <span class='Function'>⊐</span> <span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>1</span>
⟨ 0 1 2 2 0 3 ⟩
</pre>
<p><a href="couple.html">Coupling</a> the argument to the result shows how values are numbered. Each <code><span class='Number'>5</span></code> is <code><span class='Number'>0</span></code> in the result, each <code><span class='Number'>6</span></code> is <code><span class='Number'>1</span></code>, <code><span class='Number'>2</span></code> is <code><span class='Number'>2</span></code> in this particular case, and <code><span class='Number'>1</span></code> is <code><span class='Number'>3</span></code>.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omN4p+c4oqQIDXigL824oC/MuKAvzLigL814oC/MQ==">↗️</a><pre> <span class='Function'>≍</span><span class='Modifier2'>⟜</span><span class='Function'>⊐</span> <span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>1</span>
┌─
╵ 5 6 2 2 5 1
0 1 2 2 0 3
┘
</pre>
<p>Applying Classify before another self-search function will never change the result, except in the case of Deduplicate (<code><span class='Function'>⍷</span></code>), which constructs its result from cells in the argument. In particular, Classify is <a href="https://en.wikipedia.org/wiki/Idempotent">idempotent</a>, meaning that applying it twice is the same as applying it once.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oiKICAgImRiYWVkY2JjZWNiY2QiCuKIiiDiipAgImRiYWVkY2JjZWNiY2QiCgp7KPCdlY/iiaHwnZWP4oiY4oqQKSJkYmFlZGNiY2VjYmNkIn3CqCDiipDigL/iipLigL/iiIrigL/ijbc=">↗️</a><pre> <span class='Function'>∊</span> <span class='String'>"dbaedcbcecbcd"</span>
⟨ 1 1 1 1 0 1 0 0 0 0 0 0 0 ⟩
<span class='Function'>∊</span> <span class='Function'>⊐</span> <span class='String'>"dbaedcbcecbcd"</span>
⟨ 1 1 1 1 0 1 0 0 0 0 0 0 0 ⟩
<span class='Brace'>{</span><span class='Paren'>(</span><span class='Function'>𝕏≡𝕏</span><span class='Modifier2'>∘</span><span class='Function'>⊐</span><span class='Paren'>)</span><span class='String'>"dbaedcbcecbcd"</span><span class='Brace'>}</span><span class='Modifier'>¨</span> <span class='Function'>⊐</span><span class='Ligature'>‿</span><span class='Function'>⊒</span><span class='Ligature'>‿</span><span class='Function'>∊</span><span class='Ligature'>‿</span><span class='Function'>⍷</span>
⟨ 1 1 1 0 ⟩
</pre>
<h3 id="classify-and-deduplicate"><a class="header" href="#classify-and-deduplicate">Classify and Deduplicate</a></h3>
<p>Classify is also related to <a href="#deduplicate">Deduplicate</a>. In a way they are complements: applying both in sequence always gives a completely uninteresting result!</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGMg4oaQID4ieWVsbG93IuKAvyJvcmFuZ2Ui4oC/InllbGxvdyLigL8icHVycGxlIuKAvyJvcmFuZ2Ui4oC/InllbGxvdyIK4o23IOKKkCBjCuKKkCDijbcgYw==">↗️</a><pre> <span class='Function'>⊢</span> <span class='Value'>c</span> <span class='Gets'>←</span> <span class='Function'>></span><span class='String'>"yellow"</span><span class='Ligature'>‿</span><span class='String'>"orange"</span><span class='Ligature'>‿</span><span class='String'>"yellow"</span><span class='Ligature'>‿</span><span class='String'>"purple"</span><span class='Ligature'>‿</span><span class='String'>"orange"</span><span class='Ligature'>‿</span><span class='String'>"yellow"</span>
┌─
╵"yellow
orange
yellow
purple
orange
yellow"
┘
<span class='Function'>⍷</span> <span class='Function'>⊐</span> <span class='Value'>c</span>
⟨ 0 1 2 ⟩
<span class='Function'>⊐</span> <span class='Function'>⍷</span> <span class='Value'>c</span>
⟨ 0 1 2 ⟩
</pre>
<p>Applying both separately is a different story, and gives completely interesting results. These results contain all information from the original argument, as <code><span class='Function'>⍷</span></code> indicates which cells it contained and <code><span class='Function'>⊐</span></code> indicates where they were located. The function <a href="select.html">Select</a> (<code><span class='Function'>⊏</span></code>) reconstructs the argument from the two values.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4o23IGMK4oqQIGMKKOKKkGMpIOKKjyAo4o23Yyk=">↗️</a><pre> <span class='Function'>⍷</span> <span class='Value'>c</span>
┌─
╵"yellow
orange
purple"
┘
<span class='Function'>⊐</span> <span class='Value'>c</span>
⟨ 0 1 0 2 1 0 ⟩
<span class='Paren'>(</span><span class='Function'>⊐</span><span class='Value'>c</span><span class='Paren'>)</span> <span class='Function'>⊏</span> <span class='Paren'>(</span><span class='Function'>⍷</span><span class='Value'>c</span><span class='Paren'>)</span>
┌─
╵"yellow
orange
yellow
purple
orange
yellow"
┘
</pre>
<p>One way to view this relationship is from the perspective of linear algebra, where an idempotent transformation is called a "projection". That means that the argument might be any value but the result is part of a smaller class of values, and any argument from that smaller class is left the same. What arrays do the two functions project to? The result of Deduplicate is an array with no repeated major cells. The result of Classify is a list of natural numbers, but it also has an additional property: each number in the list is at most one higher than the previous numbers, and the first number is zero. This comes from the way Classify numbers the cells of its argument. When it finds a cell that hasn't appeared before (at a lower index), it always chooses the next higher number for it.</p>
<p>Applying both Classify and Deduplicate gives an array that has both properties (this isn't the case for all pairs of projections—we need to know that Classify maintains the uniqueness property for Deduplicate and vice-versa). It has no duplicate major cells, <em>and</em> it's a list of natural numbers that starts with 0 and never goes up by more than one. Taken together, these are a tight constraint! The first element of the argument has to be 0. The next can't be 0 because it's already appeared, but it can't be more than one higher—it has to be 1. The next can't be 0 or 1, and has to be 2. And so on. So the result is always <code><span class='Function'>↕</span><span class='Value'>n</span></code> for some <code><span class='Value'>n</span></code>. It's possible to determine the length as well, by noting that each function preserves the number of unique major cells in its argument. Classify does this because distinct numbers in the output correspond exactly to distinct major cells in the input; Deduplicate does this because it only removes duplicate cells, not distinct ones. So the final result is <code><span class='Function'>↕</span><span class='Value'>n</span></code>, where <code><span class='Value'>n</span></code> is the number of unique major cells in the argument.</p>
<h3 id="mark-firsts"><a class="header" href="#mark-firsts">Mark Firsts</a></h3>
<p>Mark Firsts (<code><span class='Function'>∊</span></code>) is the simplest numeric self-search function: it returns <code><span class='Number'>0</span></code> for any major cell of the argument that is a duplicate of an earlier cell and <code><span class='Number'>1</span></code> for a major cell that's the first with its value. To implement <a href="#deduplicate">Deduplicate</a> in terms of Mark Firsts, just <a href="replicate.html">filter</a> out the duplicates with <code><span class='Function'>∊</span><span class='Modifier2'>⊸</span><span class='Function'>/</span></code>.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oiKICAgM+KAvzHigL804oC/MeKAvzXigL854oC/MuKAvzbigL81CgriiIriirgvIDPigL8x4oC/NOKAvzHigL814oC/OeKAvzLigL824oC/NQ==">↗️</a><pre> <span class='Function'>∊</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>9</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>5</span>
⟨ 1 1 1 0 1 1 1 1 0 ⟩
<span class='Function'>∊</span><span class='Modifier2'>⊸</span><span class='Function'>/</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>9</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>5</span>
⟨ 3 1 4 5 9 2 6 ⟩
</pre>
<p>Mark Firsts has other uses, of course. Instead of keeping the unique values, you might remove the first of each value with <code><span class='Function'>¬</span><span class='Modifier2'>∘</span><span class='Function'>∊</span><span class='Modifier2'>⊸</span><span class='Function'>/</span></code>. You can use <code><span class='Function'>∧</span><span class='Modifier'>´</span><span class='Function'>∊</span></code> to check that an array has no duplicate major cells, or <code><span class='Function'>+</span><span class='Modifier'>´</span><span class='Function'>∊</span></code> to count the number of unique ones.</p>
<p>What about marking the elements that appear exactly once? There's a trick for this: find the cells that are firsts running both forwards (<code><span class='Function'>∊</span></code>) and <a href="reverse.html">backwards</a> (<code><span class='Function'>∊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>). Such a cell has no equal before it, nor after it, so it's unique in the entire array.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KOKIiuKIp+KIiuKMvuKMvSkgImR1Y2si4oC/ImR1Y2si4oC/InRlYWwi4oC/ImR1Y2si4oC/Imdvb3NlIg==">↗️</a><pre> <span class='Paren'>(</span><span class='Function'>∊∧∊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span><span class='Paren'>)</span> <span class='String'>"duck"</span><span class='Ligature'>‿</span><span class='String'>"duck"</span><span class='Ligature'>‿</span><span class='String'>"teal"</span><span class='Ligature'>‿</span><span class='String'>"duck"</span><span class='Ligature'>‿</span><span class='String'>"goose"</span>
⟨ 0 0 1 0 1 ⟩
</pre>
<p>Remember that you don't have to apply the result of Mark Firsts to the same array you got it from! For example, it might be useful in a database application to find unique values in a particular column but use these to filter the entire table, or one other column.</p>
<h3 id="occurrence-count"><a class="header" href="#occurrence-count">Occurrence Count</a></h3>
<p>Occurrence Count (<code><span class='Function'>⊒</span></code>) is a somewhat more sophisticated take on the idea behind Mark Firsts: instead of just testing whether a cell is a duplicate, it returns a number indicating how many previous cells match it. This means that Mark Firsts can be implemented with <code><span class='Number'>0</span><span class='Function'>=⊒</span></code>.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqSICAgMuKAvzfigL8x4oC/OOKAvzHigL834oC/MeKAvzjigL8y4oC/OOKAvzQKCuKJjeKfnOKKkiAy4oC/N+KAvzHigL844oC/MeKAvzfigL8x4oC/OOKAvzLigL844oC/NAoKMD3iipIgMuKAvzfigL8x4oC/OOKAvzHigL834oC/MeKAvzjigL8y4oC/OOKAvzQgICMgRmlyc3QgYXBwZWFyYW5jZXMgbWFya2Vk">↗️</a><pre> <span class='Function'>⊒</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>4</span>
⟨ 0 0 0 0 1 1 2 1 1 2 0 ⟩
<span class='Function'>≍</span><span class='Modifier2'>⟜</span><span class='Function'>⊒</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>4</span>
┌─
╵ 2 7 1 8 1 7 1 8 2 8 4
0 0 0 0 1 1 2 1 1 2 0
┘
<span class='Number'>0</span><span class='Function'>=⊒</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>4</span> <span class='Comment'># First appearances marked
</span>⟨ 1 1 1 1 0 0 0 0 0 0 1 ⟩
</pre>
<p>While Occurrence Count maintains more information than Mark Firsts, it's still not as much as <a href="#classify">Classify</a>. We can swap many digits around while keeping the occurrence counts the same; Classify would detect these changes.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqSICAgN+KAvzHigL8y4oC/OOKAvzfigL8x4oC/MeKAvzLigL844oC/OOKAvzQ=">↗️</a><pre> <span class='Function'>⊒</span> <span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>4</span>
⟨ 0 0 0 0 1 1 2 1 1 2 0 ⟩
</pre>
<p>One easy example with Occurrence count is to take a list that has duplicates and return exactly one copy of each duplicate element. Taking each value where the count is 1 ensures that the result has no duplicates, and that every cell that appears twice or more in the argument is represented in the result, since the second occurrence has count 1. Results are ordered by the position of these second occurrences, so a different method might be needed if the ordering is important.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KDE94oqSKeKKuC8gImFhYWFiY2RkY2Mi">↗️</a><pre> <span class='Paren'>(</span><span class='Number'>1</span><span class='Function'>=⊒</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>/</span> <span class='String'>"aaaabcddcc"</span>
"adc"
</pre>
<p>An interesting combination is Occurrence Count applied to the result of <a href="replicate.html#indices">Indices</a> (<code><span class='Function'>/</span></code>). The result counts up to each number from the argument in turn; in other symbols, it's <code><span class='Function'>∾↕</span><span class='Modifier'>¨</span></code>. This version is interesting because it doesn't create any nested arrays, just lists of natural numbers.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqSIC8gMuKAvzPigL80">↗️</a><pre> <span class='Function'>⊒</span> <span class='Function'>/</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span>
⟨ 0 1 0 1 2 0 1 2 3 ⟩
</pre>
<p>A more efficient way when <code><span class='Function'>⊒</span></code> doesn't have a fast implementation is <code><span class='Function'>/</span><span class='Paren'>(</span><span class='Number'>¯1</span><span class='Modifier2'>⊸</span><span class='Function'>⊑↕</span><span class='Modifier2'>⊸</span><span class='Function'>-⊏</span><span class='Modifier2'>⟜</span><span class='Function'>»</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Modifier'>`</span></code>, but that's clearly quite a bit more complicated.</p>
|