Unique: Difference between revisions

Jump to navigation Jump to search
717 bytes added ,  12:57, 23 November 2023
Simpler fix for length-1 case
m (ditto)
(Simpler fix for length-1 case)
 
(3 intermediate revisions by 2 users not shown)
Line 72: Line 72:
== APL model ==
== APL model ==


An APL model suggested by Kamila Szewczyk begins with an implementation for vector (rank 1) and scalar (rank 0) arrays as follows:
For [[Vector|vectors]] the following implementation based on [[Union]] can be used. It repeatedly adds cells of the argument to an accumulated unique vector <syntaxhighlight lang=apl inline>u</syntaxhighlight>, using Union so that duplicate cells are never added.
 
<syntaxhighlight lang=apl>
<syntaxhighlight lang=apl>
v ← {1/⊃∪/⊂¨⍵}
VecUnique ← {
    u ← 0↑⍵
    u ⊣ {u∪←⍵}⍤¯1 ⊢1/
}
</syntaxhighlight>
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
{{Works in|[[Dyalog APL]]}}
 
The accumulation above resembles a [[reduction]]—in fact, it is a reverse [[insertion]] (reversing is necessary when using tolerant comparison as cells need to be added in order). The following implementation written with Reduce works for non-empty [[simple]] vectors in [[Nested array model|nested]] APLs because reduction is equivalent to insertion followed by [[Enclose]] on such vectors:
It is extended to arbitrary rank inputs as follows:
<syntaxhighlight lang=apl>
 
VecUnique ← {⊃∪⍨/⌽⍵}
</syntaxhighlight>
{{Works in|[[Dyalog APL]],[[ngn/apl]]}}
It is extended to empty, nested, and arbitrary rank inputs as follows:
<syntaxhighlight lang=apl>
<syntaxhighlight lang=apl>
m ← {0∊⍴⍵:⍵⍴⍨≠∘0@⎕io⊢⍴⍵ ↑1/⊃∪/⊂¨⊂⍤¯1⊢⍵}
m ← {0=≢⍵:↑,⊃∪⍨/⌽⊂¨⊂⍤¯1⊢⍵}
</syntaxhighlight>
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
{{Works in|[[Dyalog APL]]}}
The guard checks for length zero because <syntaxhighlight lang=apl inline>∪⍨</syntaxhighlight> lacks an [[identity element]]. The [[Replicate]] call <syntaxhighlight lang=apl inline>1/⍵</syntaxhighlight> converts a scalar to a vector, and the encloses ensure that the array added by Union is always a scalar.


The guard checks for a zero element in a shape because the general model does not handle the case where the leading axis has shape of zero. While a zero element in the shape in any other place is handled by the general model, the special case is faster and less complex hence preferred. If modelling the primitive via Union is not desirable due to how similar these two primitives are, it is possible to replace this particular usage of union (not in the general case!) as follows:
If modelling the primitive via Union is not desirable due to how similar these two primitives are, it is possible to replace this particular usage of union (not generally, as it relies on the right argument being scalar) as follows:
 
<syntaxhighlight lang=apl>
<syntaxhighlight lang=apl>
m ← {0∊⍴⍵:⍵⍴⍨≠∘0@⎕io⊢⍴⍵ ↑1/(⊣,⊢⊢⍤/⍨(∧/∘.≢⍨))/⊂¨⊂⍤¯1⊢⍵}
m ← {0=≢⍵:↑,{⍺,(∧/⍺≢¨⍵)/⍵}⍨/⌽⊂¨⊂⍤¯1⊢⍵}
</syntaxhighlight>
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
{{Works in|[[Dyalog APL]]}}

Navigation menu