Remove duplicate elements: Difference between revisions
PascalABC.NET |
|||
(87 intermediate revisions by 27 users not shown) | |||
Line 14: | Line 14: | ||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="11l">V items = [‘1’, ‘2’, ‘3’, ‘a’, ‘b’, ‘c’, ‘2’, ‘3’, ‘4’, ‘b’, ‘c’, ‘d’] |
||
V unique = Array(Set(items)) |
V unique = Array(Set(items)) |
||
print(unique)</ |
print(unique)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 25: | Line 25: | ||
=={{header|360 Assembly}}== |
=={{header|360 Assembly}}== |
||
{{trans|PL/I}} |
{{trans|PL/I}} |
||
< |
<syntaxhighlight lang="360asm">* Remove duplicate elements - 18/10/2015 |
||
REMDUP CSECT |
REMDUP CSECT |
||
USING REMDUP,R15 set base register |
USING REMDUP,R15 set base register |
||
Line 72: | Line 72: | ||
PG DC CL92' ' |
PG DC CL92' ' |
||
YREGS |
YREGS |
||
END REMDUP</ |
END REMDUP</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 6 1 5 2 7 22 4 19 8 9 10 11 12</pre> |
<pre> 6 1 5 2 7 22 4 19 8 9 10 11 12</pre> |
||
Line 80: | Line 80: | ||
This routine works on arrays of bytes, and keeps track of which bytes it has seen in a 256-byte array. |
This routine works on arrays of bytes, and keeps track of which bytes it has seen in a 256-byte array. |
||
< |
<syntaxhighlight lang="8080asm"> org 100h |
||
jmp test |
jmp test |
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
Line 135: | Line 135: | ||
nl: db 13,10,'$' |
nl: db 13,10,'$' |
||
bufdef: db 127,0 |
bufdef: db 127,0 |
||
buf:</ |
buf:</syntaxhighlight> |
||
=={{header|ACL2}}== |
=={{header|ACL2}}== |
||
<lang |
<syntaxhighlight lang="lisp">(remove-duplicates xs)</syntaxhighlight> |
||
=={{header|Action!}}== |
|||
{{libheader|Action! Tool Kit}} |
|||
<syntaxhighlight lang="action!">INCLUDE "D2:SORT.ACT" ;from the Action! Tool Kit |
|||
PROC PrintArray(INT ARRAY a INT size) |
|||
INT i |
|||
Put('[) |
|||
FOR i=0 TO size-1 |
|||
DO |
|||
IF i>0 THEN Put(' ) FI |
|||
PrintI(a(i)) |
|||
OD |
|||
Put(']) PutE() |
|||
RETURN |
|||
PROC RemoveDuplicates(INT ARRAY src INT srcLen |
|||
INT ARRAY dst INT POINTER dstLen) |
|||
INT i |
|||
CHAR curr,prev |
|||
IF srcLen=0 THEN |
|||
dstLen^=0 |
|||
RETURN |
|||
FI |
|||
SortI(src,srcLen,0) |
|||
dst(0)=src(0) |
|||
dstLen^=1 prev=src(0) |
|||
FOR i=1 TO srcLen-1 |
|||
DO |
|||
curr=src(i) |
|||
IF curr#prev THEN |
|||
dst(dstLen^)=curr |
|||
dstLen^==+1 |
|||
FI |
|||
prev=curr |
|||
OD |
|||
RETURN |
|||
PROC Test(INT ARRAY src INT srcLen) |
|||
INT ARRAY dst(100) |
|||
INT dstLen |
|||
PrintE("Input array:") |
|||
PrintArray(src,srcLen) |
|||
RemoveDuplicates(src,srcLen,dst,@dstLen) |
|||
PrintE("Unique items:") |
|||
PrintArray(dst,dstLen) |
|||
PutE() |
|||
RETURN |
|||
PROC Main() |
|||
INT ARRAY src1(9)=[1 3 65534 0 12 1 65534 52 3] |
|||
INT ARRAY src2(26)=[3 2 1 3 2 5 2 1 6 3 4 2 5 3 1 5 3 5 2 1 3 7 4 5 7 6] |
|||
INT ARRAY src3(1)=[6502] |
|||
Put(125) PutE() ;clear screen |
|||
Test(src1,9) |
|||
Test(src2,26) |
|||
Test(src3,1) |
|||
RETURN</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Remove_duplicate_elements.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
Input array: |
|||
[1 3 -2 0 12 1 -2 52 3] |
|||
Unique items: |
|||
[-2 0 1 3 12 52] |
|||
Input array: |
|||
[3 2 1 3 2 5 2 1 6 3 4 2 5 3 1 5 3 5 2 |
|||
1 3 7 4 5 7 6] |
|||
Unique items: |
|||
[1 2 3 4 5 6 7] |
|||
Input array: |
|||
[6502] |
|||
Unique items: |
|||
[6502] |
|||
</pre> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
{{works with|GNAT|GPL 2018}} |
{{works with|GNAT|GPL 2018}} |
||
< |
<syntaxhighlight lang="ada">with Ada.Containers.Ordered_Sets, Ada.Text_IO; |
||
use Ada.Text_IO; |
use Ada.Text_IO; |
||
Line 157: | Line 239: | ||
Put (e'img); |
Put (e'img); |
||
end loop; |
end loop; |
||
end Duplicate;</ |
end Duplicate;</syntaxhighlight> |
||
=={{header|Aime}}== |
=={{header|Aime}}== |
||
Using an index: |
Using an index: |
||
< |
<syntaxhighlight lang="aime">index x; |
||
list(1, 2, 3, 1, 2, 3, 4, 1).ucall(i_add, 1, x, 0); |
list(1, 2, 3, 1, 2, 3, 4, 1).ucall(i_add, 1, x, 0); |
||
x.i_vcall(o_, 1, " "); |
x.i_vcall(o_, 1, " "); |
||
o_newline();</ |
o_newline();</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 1 2 3 4</pre> |
<pre> 1 2 3 4</pre> |
||
Order preserving solution: |
Order preserving solution: |
||
< |
<syntaxhighlight lang="aime">index x; |
||
for (, integer a in list(8, 2, 1, 8, 2, 1, 4, 8)) { |
for (, integer a in list(8, 2, 1, 8, 2, 1, 4, 8)) { |
||
Line 176: | Line 258: | ||
} |
} |
||
} |
} |
||
o_newline();</ |
o_newline();</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 8 2 1 4</pre> |
<pre> 8 2 1 4</pre> |
||
Line 182: | Line 264: | ||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
Using the associative array code from [[Associative_array/Iteration#ALGOL_68]] |
Using the associative array code from [[Associative_array/Iteration#ALGOL_68]] |
||
< |
<syntaxhighlight lang="algol68"># use the associative array in the Associate array/iteration task # |
||
# this example uses strings - for other types, the associative # |
# this example uses strings - for other types, the associative # |
||
# array modes AAELEMENT and AAKEY should be modified as required # |
# array modes AAELEMENT and AAKEY should be modified as required # |
||
Line 213: | Line 295: | ||
# test the duplicate removal # |
# test the duplicate removal # |
||
print( ( remove duplicates( ( "A", "B", "D", "A", "C", "F", "F", "A" ) ), newline ) ) |
print( ( remove duplicates( ( "A", "B", "D", "A", "C", "F", "F", "A" ) ), newline ) ) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Amazing Hopper}}== |
|||
<syntaxhighlight lang="amazing hopper"> |
|||
#include <hopper.h> |
|||
main: |
|||
x=-1 |
|||
{30} rand array (x), mulby(10), ceil, mov(x) |
|||
{"Original Array:\n",x}, println |
|||
{x}array(SORT), |
|||
{x}sets(UNIQUE), mov(x) |
|||
{"Final array:\n",x}, println |
|||
y={} |
|||
{"C","Go","Go","C","Cobol","java","Ada"} pushall(y) |
|||
{"java","algol-68","C","java","fortran"} pushall(y) |
|||
{"\nOriginal Array:\n",y}, println |
|||
{y}array(SORT), |
|||
{y}sets(UNIQUE), mov(y) |
|||
{"Final array:\n",y}, println |
|||
exit(0) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Original Array: |
|||
3 9 1 10 3 7 6 5 2 7 4 7 4 2 2 2 2 8 2 10 4 9 2 4 9 3 4 3 4 7 |
|||
Final array: |
|||
1 2 3 4 5 6 7 8 9 10 |
|||
Original Array: |
|||
C Go Go C Cobol java Ada java algol-68 C java fortran |
|||
Final array: |
|||
Ada C Cobol Go algol-68 fortran java |
|||
</pre> |
|||
=={{header|APL}}== |
=={{header|APL}}== |
||
Line 219: | Line 334: | ||
{{works with|GNU APL}} |
{{works with|GNU APL}} |
||
The primitive monad ∪ means "unique", so: |
The primitive monad ∪ means "unique", so: |
||
< |
<syntaxhighlight lang="apl">∪ 1 2 3 1 2 3 4 1 |
||
1 2 3 4</ |
1 2 3 4</syntaxhighlight> |
||
{{works with|APL2}} |
{{works with|APL2}} |
||
{{works with|GNU APL}} |
{{works with|GNU APL}} |
||
< |
<syntaxhighlight lang="apl">w←1 2 3 1 2 3 4 1 |
||
((⍳⍨w)=⍳⍴w)/w |
((⍳⍨w)=⍳⍴w)/w |
||
1 2 3 4</ |
1 2 3 4</syntaxhighlight> |
||
=={{header|AppleScript}}== |
=={{header|AppleScript}}== |
||
===Idiomatic=== |
===Idiomatic=== |
||
< |
<syntaxhighlight lang="applescript">unique({1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"}) |
||
on unique(x) |
on unique(x) |
||
Line 238: | Line 353: | ||
end repeat |
end repeat |
||
return R |
return R |
||
end unique</ |
end unique</syntaxhighlight> |
||
---- |
---- |
||
===Idiomatic 2 (more robust)=== |
===Idiomatic 2 (more robust)=== |
||
While it's quite common to see 'is in', 'is not in', 'contains', and 'does not contain' used in the above way for convenience when the scripter knows the code will only be used to check for simple objects, the commands actually compare ''sections of list'' rather than individual elements. |
While it's quite common to see 'is in', 'is not in', 'contains', and 'does not contain' used in the above way for convenience when the scripter knows the code will only be used to check for simple objects, the commands actually compare ''sections of list'' rather than individual elements. |
||
< |
<syntaxhighlight lang="applescript">{1, 2, 3, {4, 5}} contains {2, 3} --> true |
||
{1, 2, 3, {4, 5}} contains {4, 5} --> false |
{1, 2, 3, {4, 5}} contains {4, 5} --> false |
||
{1, 2, 3, {4, 5}} contains {{4, 5}} --> true</ |
{1, 2, 3, {4, 5}} contains {{4, 5}} --> true</syntaxhighlight> |
||
If the search term presented is anything other than a list, it's silently coerced to one for the search. |
If the search term presented is anything other than a list, it's silently coerced to one for the search. |
||
< |
<syntaxhighlight lang="applescript">3 is in {1, 2, 3, {4, 5}} --> {3} is in {1, 2, 3, {4, 5}} --> true</syntaxhighlight> |
||
So for robustness in case the elements sought may already be lists, or records, it's best to wrap them explicitly in list braces. |
So for robustness in case the elements sought may already be lists, or records, it's best to wrap them explicitly in list braces. |
||
< |
<syntaxhighlight lang="applescript">unique({1, 2, 3, "a", "b", "c", 2, 3, 4, "c", {b:"c"}, {"c"}, "c", "d"}) |
||
on unique(x) |
on unique(x) |
||
Line 262: | Line 377: | ||
end repeat |
end repeat |
||
return R |
return R |
||
end unique</ |
end unique</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
< |
<syntaxhighlight lang="applescript">{1, 2, 3, "a", "b", "c", 4, {b:"c"}, {"c"}, "d"}</syntaxhighlight> |
||
---- |
---- |
||
===Functional=== |
===Functional=== |
||
Line 276: | Line 391: | ||
{{trans|Haskell}} |
{{trans|Haskell}} |
||
< |
<syntaxhighlight lang="applescript">-- CASE-INSENSITIVE UNIQUE ELEMENTS ------------------------------------------ |
||
-- nub :: [a] -> [a] |
-- nub :: [a] -> [a] |
||
Line 367: | Line 482: | ||
set my text item delimiters to dlm |
set my text item delimiters to dlm |
||
return lstParts |
return lstParts |
||
end splitOn</ |
end splitOn</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
< |
<syntaxhighlight lang="applescript">{"4 3 2 8 0 1 9 5 7 6", "abc "}</syntaxhighlight> |
||
---- |
|||
===AppleScriptObjC=== |
|||
<syntaxhighlight lang="applescript">use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later |
|||
use framework "Foundation" |
|||
set aList to {1, 2, 3, "a", "b", "c", 2, 3, 4, "c", {b:"c"}, {"c"}, "c", "d"} |
|||
set orderedSet to current application's class "NSOrderedSet"'s orderedSetWithArray:(aList) |
|||
return orderedSet's array() as list</syntaxhighlight> |
|||
{{output}} |
|||
<syntaxhighlight lang="applescript">{1, 2, 3, "a", "b", "c", 4, {b:"c"}, {"c"}, "d"}</syntaxhighlight> |
|||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="rebol">arr: [1 2 3 2 1 2 3 4 5 3 2 1] |
|||
print unique arr</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 2 3 4 5</pre> |
|||
=={{header|ATS}}== |
|||
=== ATS2 implementation for values having an ''equality'' predicate === |
|||
This method runs no worse than O(n*n) in the number of elements. It is an example of the brute-force technique. |
|||
The implementation is for non-linear types, only. I implement the predicate as a non-linear closure. |
|||
<syntaxhighlight lang="ats"> |
|||
(* Remove duplicate elements. |
|||
This implementation is for elements that have an "equals" (or |
|||
"equivalence") predicate. It runs O(n*n) in the number of |
|||
elements. *) |
|||
#include "share/atspre_staload.hats" |
|||
(* How the remove_dups template function will be called. *) |
|||
extern fn {a : t@ype} |
|||
remove_dups |
|||
{n : int} |
|||
(eq : (a, a) -<cloref> bool, |
|||
src : arrayref (a, n), |
|||
n : size_t n, |
|||
dst : arrayref (a, n), |
|||
m : &size_t? >> size_t m) |
|||
:<!refwrt> #[m : nat | m <= n] |
|||
void |
|||
(* An implementation of the remove_dups template function. *) |
|||
implement {a} |
|||
remove_dups {n} (eq, src, n, dst, m) = |
|||
if n = i2sz 0 then |
|||
m := i2sz 0 |
|||
else |
|||
let |
|||
fun |
|||
peruse_src |
|||
{i : int | 1 <= i; i <= n} |
|||
{j : int | 1 <= j; j <= i} |
|||
.<n - i>. |
|||
(i : size_t i, |
|||
j : size_t j) |
|||
:<!refwrt> [m : int | 1 <= m; m <= n] |
|||
size_t m = |
|||
let |
|||
fun |
|||
already_seen |
|||
{k : int | 0 <= k; k <= j} |
|||
.<j - k>. |
|||
(x : a, |
|||
k : size_t k) |
|||
:<!ref> bool = |
|||
if k = j then |
|||
false |
|||
else if eq (x, dst[k]) then |
|||
true |
|||
else |
|||
already_seen (x, succ k) |
|||
in |
|||
if i = n then |
|||
j |
|||
else if already_seen (src[i], i2sz 0) then |
|||
peruse_src (succ i, j) |
|||
else |
|||
begin |
|||
dst[j] := src[i]; |
|||
peruse_src (succ i, succ j) |
|||
end |
|||
end |
|||
prval () = lemma_arrayref_param src (* Prove 0 <= n. *) |
|||
in |
|||
dst[0] := src[0]; |
|||
m := peruse_src (i2sz 1, i2sz 1) |
|||
end |
|||
implement (* A demonstration with strings. *) |
|||
main0 () = |
|||
let |
|||
val eq = lam (x : string, y : string) : bool =<cloref> (x = y) |
|||
val src = |
|||
arrayref_make_list<string> |
|||
(10, $list ("a", "c", "b", "e", "a", |
|||
"a", "d", "d", "b", "c")) |
|||
val dst = arrayref_make_elt<string> (i2sz 10, "?") |
|||
var m : size_t |
|||
in |
|||
remove_dups<string> (eq, src, i2sz 10, dst, m); |
|||
let |
|||
prval [m : int] EQINT () = eqint_make_guint m |
|||
var i : natLte m |
|||
in |
|||
for (i := 0; i2sz i <> m; i := succ i) |
|||
print! (" ", dst[i] : string); |
|||
println! () |
|||
end |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> a c b e d</pre> |
|||
=== ATS2 implementation for linear values having an ''equality'' predicate === |
|||
This method runs no worse than O(n*n) in the number of elements. It is another example of the brute-force technique. |
|||
This implementation can handle elements of linear type. I implement the predicate as a template function. |
|||
There are two interfaces: one for an array, and one for a linked list. |
|||
<syntaxhighlight lang="ats"> |
|||
(* Remove duplicate elements. |
|||
This implementation is for elements that have an "equals" (or |
|||
"equivalence") predicate. It runs O(n*n) in the number of |
|||
elements. It uses a linked list and supports linear types. |
|||
The equality predicate is implemented as a template function. *) |
|||
#include "share/atspre_staload.hats" |
|||
staload UN = "prelude/SATS/unsafe.sats" |
|||
#define NIL list_vt_nil () |
|||
#define :: list_vt_cons |
|||
(*------------------------------------------------------------------*) |
|||
(* Interfaces *) |
|||
extern fn {a : vt@ype} |
|||
array_remove_dups |
|||
{n : int} |
|||
{p_arr : addr} |
|||
(pf_arr : array_v (a, p_arr, n) | |
|||
p_arr : ptr p_arr, |
|||
n : size_t n) |
|||
:<!wrt> [m : nat | m <= n] |
|||
@(array_v (a, p_arr, m), |
|||
array_v (a?, p_arr + (m * sizeof a), n - m) | |
|||
size_t m) |
|||
extern fn {a : vt@ype} |
|||
list_vt_remove_dups |
|||
{n : int} |
|||
(lst : list_vt (a, n)) |
|||
:<!wrt> [m : nat | m <= n] |
|||
list_vt (a, m) |
|||
extern fn {a : vt@ype} |
|||
remove_dups$eq : |
|||
(&a, &a) -<> bool |
|||
extern fn {a : vt@ype} |
|||
remove_dups$clear : |
|||
(&a >> a?) -< !wrt > void |
|||
(*------------------------------------------------------------------*) |
|||
(* Implementation of array_remove_dups *) |
|||
(* The implementation for arrays converts to a list_vt, does the |
|||
removal duplicates, and then writes the data back into the original |
|||
array. *) |
|||
implement {a} |
|||
array_remove_dups {n} {p_arr} (pf_arr | p_arr, n) = |
|||
let |
|||
var lst = array_copy_to_list_vt<a> (!p_arr, n) |
|||
var m : int |
|||
val lst = list_vt_remove_dups<a> lst |
|||
val m = list_vt_length lst |
|||
prval [m : int] EQINT () = eqint_make_gint m |
|||
prval @(pf_uniq, pf_rest) = |
|||
array_v_split {a?} {p_arr} {n} {m} pf_arr |
|||
val () = array_copy_from_list_vt<a> (!p_arr, lst) |
|||
in |
|||
@(pf_uniq, pf_rest | i2sz m) |
|||
end |
|||
(*------------------------------------------------------------------*) |
|||
(* Implementation of list_vt_remove_dups *) |
|||
(* The list is worked on "in place". That is, no nodes are copied or |
|||
moved to new locations, except those that are removed and freed. *) |
|||
fn {a : vt@ype} |
|||
remove_equal_elements |
|||
{n : int} |
|||
(x : &a, |
|||
lst : &list_vt (a, n) >> list_vt (a, m)) |
|||
:<!wrt> #[m : nat | m <= n] |
|||
void = |
|||
let |
|||
fun {a : vt@ype} |
|||
remove_elements |
|||
{n : nat} |
|||
.<n>. |
|||
(x : &a, |
|||
lst : &list_vt (a, n) >> list_vt (a, m)) |
|||
:<!wrt> #[m : nat | m <= n] |
|||
void = |
|||
case+ lst of |
|||
| NIL => () |
|||
| @ (head :: tail) => |
|||
if remove_dups$eq (head, x) then |
|||
let |
|||
val new_lst = tail |
|||
val () = remove_dups$clear<a> head |
|||
val () = free@{a}{0} lst |
|||
val () = lst := new_lst |
|||
in |
|||
remove_elements {n - 1} (x, lst) |
|||
end |
|||
else |
|||
let |
|||
val () = remove_elements {n - 1} (x, tail) |
|||
prval () = fold@ lst |
|||
in |
|||
end |
|||
prval () = lemma_list_vt_param lst |
|||
in |
|||
remove_elements {n} (x, lst) |
|||
end |
|||
fn {a : vt@ype} |
|||
remove_dups |
|||
{n : int} |
|||
(lst : &list_vt (a, n) >> list_vt (a, m)) |
|||
:<!wrt> #[m : nat | m <= n] |
|||
void = |
|||
let |
|||
fun |
|||
rmv_dups {n : nat} |
|||
.<n>. |
|||
(lst : &list_vt (a, n) >> list_vt (a, m)) |
|||
:<!wrt> #[m : nat | m <= n] |
|||
void = |
|||
case+ lst of |
|||
| NIL => () |
|||
| head :: NIL => () |
|||
| @ head :: tail => |
|||
let |
|||
val () = remove_equal_elements (head, tail) |
|||
val () = rmv_dups tail |
|||
prval () = fold@ lst |
|||
in |
|||
end |
|||
prval () = lemma_list_vt_param lst |
|||
in |
|||
rmv_dups {n} lst |
|||
end |
|||
implement {a} |
|||
list_vt_remove_dups {n} lst = |
|||
let |
|||
var lst = lst |
|||
in |
|||
remove_dups {n} lst; |
|||
lst |
|||
end |
|||
(*------------------------------------------------------------------*) |
|||
implement |
|||
remove_dups$eq<Strptr1> (s, t) = |
|||
($UN.strptr2string s = $UN.strptr2string t) |
|||
implement |
|||
remove_dups$clear<Strptr1> s = |
|||
strptr_free s |
|||
implement |
|||
array_uninitize$clear<Strptr1> (i, s) = |
|||
strptr_free s |
|||
implement |
|||
fprint_ref<Strptr1> (outf, s) = |
|||
fprint! (outf, $UN.strptr2string s) |
|||
implement (* A demonstration with linear strings. *) |
|||
main0 () = |
|||
let |
|||
#define N 10 |
|||
val data = |
|||
$list_vt{Strptr1} |
|||
(string0_copy "a", string0_copy "c", string0_copy "b", |
|||
string0_copy "e", string0_copy "a", string0_copy "a", |
|||
string0_copy "d", string0_copy "d", string0_copy "b", |
|||
string0_copy "c") |
|||
var arr : @[Strptr1][N] |
|||
val () = array_copy_from_list_vt<Strptr1> (arr, data) |
|||
prval pf_arr = view@ arr |
|||
val p_arr = addr@ arr |
|||
val [m : int] |
|||
@(pf_uniq, pf_abandoned | m) = |
|||
array_remove_dups<Strptr1> (pf_arr | p_arr, i2sz N) |
|||
val () = fprint_array_sep<Strptr1> (stdout_ref, !p_arr, m, " ") |
|||
val () = println! () |
|||
val () = array_uninitize<Strptr1> (!p_arr, m) |
|||
prval () = view@ arr := |
|||
array_v_unsplit (pf_uniq, pf_abandoned) |
|||
in |
|||
end |
|||
(*------------------------------------------------------------------*) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> a c b e d</pre> |
|||
=== ATS2 implementation for values having both ''order'' and ''equality'' predicates === |
|||
Sort the elements and then keep only the first element of each run of equal elements. |
|||
This method is limited in speed by the speed of the sorting algorithm. That can vary greatly according to algorithm and circumstances, but typically is much better than O(n*n). Below (simply because it is convenient) I use the quicksort that is in the ATS2 prelude. |
|||
<syntaxhighlight lang="ats"> |
|||
(* Remove duplicate elements. |
|||
The elements are sorted and then only unique values are kept. *) |
|||
#include "share/atspre_staload.hats" |
|||
(* How the remove_dups template function will be called. *) |
|||
extern fn {a : t@ype} |
|||
remove_dups |
|||
{n : int} |
|||
(lt : (a, a) -<cloref> bool, (* "less than" *) |
|||
eq : (a, a) -<cloref> bool, (* "equals" *) |
|||
src : arrayref (a, n), |
|||
n : size_t n, |
|||
dst : arrayref (a, n), |
|||
m : &size_t? >> size_t m) |
|||
: #[m : nat | m <= n] |
|||
void |
|||
implement {a} |
|||
remove_dups {n} (lt, eq, src, n, dst, m) = |
|||
if n = i2sz 0 then |
|||
m := i2sz 0 |
|||
else |
|||
let |
|||
prval () = lemma_arrayref_param src (* Prove 0 <= n. *) |
|||
(* Sort a copy of src. *) |
|||
val arr = arrayptr_refize (arrayref_copy (src, n)) |
|||
implement array_quicksort$cmp<a> (x, y) = |
|||
if x \lt y then ~1 else 1 |
|||
val () = arrayref_quicksort<a> (arr, n) |
|||
(* Copy only the first element of each run of equal elements. *) |
|||
val () = dst[0] := arr[0] |
|||
fun |
|||
loop {i : int | 1 <= i; i <= n} |
|||
{j : int | 1 <= j; j <= i} |
|||
.<n - i>. |
|||
(i : size_t i, |
|||
j : size_t j) |
|||
: [m : int | 1 <= m; m <= n] |
|||
size_t m = |
|||
if i = n then |
|||
j |
|||
else if arr[pred i] \eq arr[i] then |
|||
loop (succ i, j) |
|||
else |
|||
begin |
|||
dst[j] := arr[i]; |
|||
loop (succ i, succ j) |
|||
end |
|||
val () = m := loop (i2sz 1, i2sz 1) |
|||
in |
|||
end |
|||
implement (* A demonstration. *) |
|||
main0 () = |
|||
let |
|||
val src = |
|||
arrayref_make_list<string> |
|||
(10, $list ("a", "c", "b", "e", "a", |
|||
"a", "d", "d", "b", "c")) |
|||
val dst = arrayref_make_elt<string> (i2sz 10, "?") |
|||
var m : size_t |
|||
in |
|||
remove_dups<string> (lam (x, y) => x < y, |
|||
lam (x, y) => x = y, |
|||
src, i2sz 10, dst, m); |
|||
let |
|||
prval [m : int] EQINT () = eqint_make_guint m |
|||
var i : natLte m |
|||
in |
|||
for (i := 0; i2sz i <> m; i := succ i) |
|||
print! (" ", dst[i]); |
|||
println! () |
|||
end |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> a b c d e</pre> |
|||
=== ATS2 implementation using a radix sort === |
|||
This method runs in O(nw) time, where n is the number of elements n and w is a factor that is constant for elements that are fixed-size integers. |
|||
The implementation is for unsigned integers and puts the unique numbers into a second array in ascending order. |
|||
Radix sorting can sort an array of elements only into the encoding order of their keys, but that is a common case. Here the only reason to sort at all is to quickly eliminate duplicates. |
|||
<syntaxhighlight lang="ats"> |
|||
(* Remove duplicate elements. |
|||
The best sorting algorithms, it is said, are O(n log n) and require |
|||
an order predicate. |
|||
But this is true only for a general sorting routine. A radix sort |
|||
for fixed-size integers is O(n), and requires no order predicate. |
|||
Here I use such a radix sort. *) |
|||
#include "share/atspre_staload.hats" |
|||
staload UN = "prelude/SATS/unsafe.sats" |
|||
(* How the remove_dups template function will be called. *) |
|||
extern fn {tk : tkind} |
|||
remove_dups |
|||
{n : int} |
|||
(src : arrayref (g0uint tk, n), |
|||
n : size_t n, |
|||
dst : arrayref (g0uint tk, n), |
|||
m : &size_t? >> size_t m) |
|||
: #[m : nat | m <= n] |
|||
void |
|||
(*------------------------------------------------------------------*) |
|||
(* A radix sort for unsigned integers, copied from my contribution to |
|||
the radix sort task. *) |
|||
extern fn {a : vt@ype} |
|||
{tk : tkind} |
|||
g0uint_radix_sort |
|||
{n : int} |
|||
(arr : &array (a, n) >> _, |
|||
n : size_t n) |
|||
:<!wrt> void |
|||
extern fn {a : vt@ype} |
|||
{tk : tkind} |
|||
g0uint_radix_sort$key |
|||
{n : int} |
|||
{i : nat | i < n} |
|||
(arr : &RD(array (a, n)), |
|||
i : size_t i) |
|||
:<> g0uint tk |
|||
fn {} |
|||
bin_sizes_to_indices |
|||
(bin_indices : &array (size_t, 256) >> _) |
|||
:<!wrt> void = |
|||
let |
|||
fun |
|||
loop {i : int | i <= 256} |
|||
{accum : int} |
|||
.<256 - i>. |
|||
(bin_indices : &array (size_t, 256) >> _, |
|||
i : size_t i, |
|||
accum : size_t accum) |
|||
:<!wrt> void = |
|||
if i <> i2sz 256 then |
|||
let |
|||
prval () = lemma_g1uint_param i |
|||
val elem = bin_indices[i] |
|||
in |
|||
if elem = i2sz 0 then |
|||
loop (bin_indices, succ i, accum) |
|||
else |
|||
begin |
|||
bin_indices[i] := accum; |
|||
loop (bin_indices, succ i, accum + g1ofg0 elem) |
|||
end |
|||
end |
|||
in |
|||
loop (bin_indices, i2sz 0, i2sz 0) |
|||
end |
|||
fn {a : vt@ype} |
|||
{tk : tkind} |
|||
count_entries |
|||
{n : int} |
|||
{shift : nat} |
|||
(arr : &RD(array (a, n)), |
|||
n : size_t n, |
|||
bin_indices : &array (size_t?, 256) |
|||
>> array (size_t, 256), |
|||
all_expended : &bool? >> bool, |
|||
shift : int shift) |
|||
:<!wrt> void = |
|||
let |
|||
fun |
|||
loop {i : int | i <= n} |
|||
.<n - i>. |
|||
(arr : &RD(array (a, n)), |
|||
bin_indices : &array (size_t, 256) >> _, |
|||
all_expended : &bool >> bool, |
|||
i : size_t i) |
|||
:<!wrt> void = |
|||
if i <> n then |
|||
let |
|||
prval () = lemma_g1uint_param i |
|||
val key : g0uint tk = g0uint_radix_sort$key<a><tk> (arr, i) |
|||
val key_shifted = key >> shift |
|||
val digit = ($UN.cast{uint} key_shifted) land 255U |
|||
val [digit : int] digit = g1ofg0 digit |
|||
extern praxi set_range : |
|||
() -<prf> [0 <= digit; digit <= 255] void |
|||
prval () = set_range () |
|||
val count = bin_indices[digit] |
|||
val () = bin_indices[digit] := succ count |
|||
in |
|||
all_expended := all_expended * iseqz key_shifted; |
|||
loop (arr, bin_indices, all_expended, succ i) |
|||
end |
|||
prval () = lemma_array_param arr |
|||
in |
|||
array_initize_elt<size_t> (bin_indices, i2sz 256, i2sz 0); |
|||
all_expended := true; |
|||
loop (arr, bin_indices, all_expended, i2sz 0) |
|||
end |
|||
fn {a : vt@ype} |
|||
{tk : tkind} |
|||
sort_by_digit |
|||
{n : int} |
|||
{shift : nat} |
|||
(arr1 : &RD(array (a, n)), |
|||
arr2 : &array (a, n) >> _, |
|||
n : size_t n, |
|||
all_expended : &bool? >> bool, |
|||
shift : int shift) |
|||
:<!wrt> void = |
|||
let |
|||
var bin_indices : array (size_t, 256) |
|||
in |
|||
count_entries<a><tk> (arr1, n, bin_indices, all_expended, shift); |
|||
if all_expended then |
|||
() |
|||
else |
|||
let |
|||
fun |
|||
rearrange {i : int | i <= n} |
|||
.<n - i>. |
|||
(arr1 : &RD(array (a, n)), |
|||
arr2 : &array (a, n) >> _, |
|||
bin_indices : &array (size_t, 256) >> _, |
|||
i : size_t i) |
|||
:<!wrt> void = |
|||
if i <> n then |
|||
let |
|||
prval () = lemma_g1uint_param i |
|||
val key = g0uint_radix_sort$key<a><tk> (arr1, i) |
|||
val key_shifted = key >> shift |
|||
val digit = ($UN.cast{uint} key_shifted) land 255U |
|||
val [digit : int] digit = g1ofg0 digit |
|||
extern praxi set_range : |
|||
() -<prf> [0 <= digit; digit <= 255] void |
|||
prval () = set_range () |
|||
val [j : int] j = g1ofg0 bin_indices[digit] |
|||
(* One might wish to get rid of this assertion somehow, |
|||
to eliminate the branch, should it prove a |
|||
problem. *) |
|||
val () = $effmask_exn assertloc (j < n) |
|||
val p_dst = ptr_add<a> (addr@ arr2, j) |
|||
and p_src = ptr_add<a> (addr@ arr1, i) |
|||
val _ = $extfcall (ptr, "memcpy", p_dst, p_src, |
|||
sizeof<a>) |
|||
val () = bin_indices[digit] := succ (g0ofg1 j) |
|||
in |
|||
rearrange (arr1, arr2, bin_indices, succ i) |
|||
end |
|||
prval () = lemma_array_param arr1 |
|||
in |
|||
bin_sizes_to_indices<> bin_indices; |
|||
rearrange (arr1, arr2, bin_indices, i2sz 0) |
|||
end |
|||
end |
|||
fn {a : vt@ype} |
|||
{tk : tkind} |
|||
g0uint_sort {n : pos} |
|||
(arr1 : &array (a, n) >> _, |
|||
arr2 : &array (a, n) >> _, |
|||
n : size_t n) |
|||
:<!wrt> void = |
|||
let |
|||
fun |
|||
loop {idigit_max, idigit : nat | idigit <= idigit_max} |
|||
.<idigit_max - idigit>. |
|||
(arr1 : &array (a, n) >> _, |
|||
arr2 : &array (a, n) >> _, |
|||
from1to2 : bool, |
|||
idigit_max : int idigit_max, |
|||
idigit : int idigit) |
|||
:<!wrt> void = |
|||
if idigit = idigit_max then |
|||
begin |
|||
if ~from1to2 then |
|||
let |
|||
val _ = |
|||
$extfcall (ptr, "memcpy", addr@ arr1, addr@ arr2, |
|||
sizeof<a> * n) |
|||
in |
|||
end |
|||
end |
|||
else if from1to2 then |
|||
let |
|||
var all_expended : bool |
|||
in |
|||
sort_by_digit<a><tk> (arr1, arr2, n, all_expended, |
|||
8 * idigit); |
|||
if all_expended then |
|||
() |
|||
else |
|||
loop (arr1, arr2, false, idigit_max, succ idigit) |
|||
end |
|||
else |
|||
let |
|||
var all_expended : bool |
|||
in |
|||
sort_by_digit<a><tk> (arr2, arr1, n, all_expended, |
|||
8 * idigit); |
|||
if all_expended then |
|||
let |
|||
val _ = |
|||
$extfcall (ptr, "memcpy", addr@ arr1, addr@ arr2, |
|||
sizeof<a> * n) |
|||
in |
|||
end |
|||
else |
|||
loop (arr1, arr2, true, idigit_max, succ idigit) |
|||
end |
|||
in |
|||
loop (arr1, arr2, true, sz2i sizeof<g1uint tk>, 0) |
|||
end |
|||
#define SIZE_THRESHOLD 256 |
|||
extern praxi |
|||
unsafe_cast_array |
|||
{a : vt@ype} |
|||
{b : vt@ype} |
|||
{n : int} |
|||
(arr : &array (b, n) >> array (a, n)) |
|||
:<prf> void |
|||
implement {a} {tk} |
|||
g0uint_radix_sort {n} (arr, n) = |
|||
if n <> 0 then |
|||
let |
|||
prval () = lemma_array_param arr |
|||
fn |
|||
sort {n : pos} |
|||
(arr1 : &array (a, n) >> _, |
|||
arr2 : &array (a, n) >> _, |
|||
n : size_t n) |
|||
:<!wrt> void = |
|||
g0uint_sort<a><tk> (arr1, arr2, n) |
|||
in |
|||
if n <= SIZE_THRESHOLD then |
|||
let |
|||
var arr2 : array (a, SIZE_THRESHOLD) |
|||
prval @(pf_left, pf_right) = |
|||
array_v_split {a?} {..} {SIZE_THRESHOLD} {n} (view@ arr2) |
|||
prval () = view@ arr2 := pf_left |
|||
prval () = unsafe_cast_array{a} arr2 |
|||
val () = sort (arr, arr2, n) |
|||
prval () = unsafe_cast_array{a?} arr2 |
|||
prval () = view@ arr2 := |
|||
array_v_unsplit (view@ arr2, pf_right) |
|||
in |
|||
end |
|||
else |
|||
let |
|||
val @(pf_arr2, pfgc_arr2 | p_arr2) = array_ptr_alloc<a> n |
|||
macdef arr2 = !p_arr2 |
|||
prval () = unsafe_cast_array{a} arr2 |
|||
val () = sort (arr, arr2, n) |
|||
prval () = unsafe_cast_array{a?} arr2 |
|||
val () = array_ptr_free (pf_arr2, pfgc_arr2 | p_arr2) |
|||
in |
|||
end |
|||
end |
|||
(*------------------------------------------------------------------*) |
|||
(* An implementation of the remove_dups template function, which also |
|||
sorts the elements. *) |
|||
implement {tk} |
|||
remove_dups {n} (src, n, dst, m) = |
|||
if n = i2sz 0 then |
|||
m := i2sz 0 |
|||
else |
|||
let |
|||
prval () = lemma_arrayref_param src (* Prove 0 <= n. *) |
|||
(* Sort a copy of src. *) |
|||
val arrptr = arrayref_copy (src, n) |
|||
val @(pf_arr | p_arr) = arrayptr_takeout_viewptr arrptr |
|||
val () = g0uint_radix_sort<g0uint tk><tk> (!p_arr, n) |
|||
prval () = arrayptr_addback (pf_arr | arrptr) |
|||
(* Copy only the first element of each run of equals. *) |
|||
val () = dst[0] := arrptr[0] |
|||
fun |
|||
loop {i : int | 1 <= i; i <= n} |
|||
{j : int | 1 <= j; j <= i} |
|||
.<n - i>. |
|||
(arrptr : !arrayptr (g0uint tk, n), |
|||
i : size_t i, |
|||
j : size_t j) |
|||
: [m : int | 1 <= m; m <= n] |
|||
size_t m = |
|||
if i = n then |
|||
j |
|||
else if arrptr[pred i] = arrptr[i] then |
|||
loop (arrptr, succ i, j) |
|||
else |
|||
begin |
|||
dst[j] := arrptr[i]; |
|||
loop (arrptr, succ i, succ j) |
|||
end |
|||
val () = m := loop (arrptr, i2sz 1, i2sz 1) |
|||
val () = arrayptr_free arrptr |
|||
in |
|||
end |
|||
(*------------------------------------------------------------------*) |
|||
(* A demonstration. *) |
|||
implement |
|||
main0 () = |
|||
let |
|||
implement |
|||
g0uint_radix_sort$key<uint><uintknd> (arr, i) = |
|||
arr[i] |
|||
val src = |
|||
arrayref_make_list<uint> |
|||
(10, $list (1U, 3U, 2U, 5U, 1U, 1U, 4U, 4U, 2U, 3U)) |
|||
val dst = arrayref_make_elt<uint> (i2sz 10, 123456789U) |
|||
var m : size_t |
|||
in |
|||
remove_dups<uintknd> (src, i2sz 10, dst, m); |
|||
let |
|||
prval [m : int] EQINT () = eqint_make_guint m |
|||
var i : natLte m |
|||
in |
|||
for (i := 0; i2sz i <> m; i := succ i) |
|||
print! (" ", dst[i]); |
|||
println! () |
|||
end |
|||
end |
|||
(*------------------------------------------------------------------*) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1 2 3 4 5</pre> |
|||
=== ATS2 implementation using a hash table === |
|||
The speed of this method depends on the speed of the hash table. |
|||
<syntaxhighlight lang="ats"> |
|||
(* Remove duplicate elements. |
|||
Elements already seen are put into a hash table. *) |
|||
#include "share/atspre_staload.hats" |
|||
(* Use hash tables from the libats/ML library. *) |
|||
staload "libats/ML/SATS/hashtblref.sats" |
|||
staload _ = "libats/ML/DATS/hashtblref.dats" |
|||
staload _ = "libats/DATS/hashfun.dats" |
|||
staload _ = "libats/DATS/hashtbl_chain.dats" |
|||
staload _ = "libats/DATS/linmap_list.dats" |
|||
(* How the remove_dups template function will be called. *) |
|||
extern fn {key, a : t@ype} |
|||
remove_dups |
|||
{n : int} |
|||
(key : a -<cloref> key, |
|||
src : arrayref (a, n), |
|||
n : size_t n, |
|||
dst : arrayref (a, n), |
|||
m : &size_t? >> size_t m) |
|||
: #[m : nat | m <= n] |
|||
void |
|||
implement {key, a} |
|||
remove_dups {n} (key, src, n, dst, m) = |
|||
if n = i2sz 0 then |
|||
m := i2sz 0 |
|||
else |
|||
let |
|||
prval () = lemma_arrayref_param src (* Prove 0 <= n. *) |
|||
fun |
|||
loop {i : nat | i <= n} |
|||
{j : nat | j <= i} |
|||
.<n - i>. |
|||
(ht : hashtbl (key, a), |
|||
i : size_t i, |
|||
j : size_t j) |
|||
: [m : nat | m <= n] |
|||
size_t m = |
|||
if i = n then |
|||
j |
|||
else |
|||
let |
|||
val x = src[i] |
|||
val k = key x |
|||
in |
|||
case+ hashtbl_search<key, a> (ht, k) of |
|||
| ~ None_vt () => |
|||
begin (* An element not yet encountered. Copy it. *) |
|||
hashtbl_insert_any<key, a> (ht, k, x); |
|||
dst[j] := x; |
|||
loop (ht, succ i, succ j) |
|||
end |
|||
| ~ Some_vt _ => |
|||
begin (* An element already encountered. Skip it. *) |
|||
loop (ht, succ i, j) |
|||
end |
|||
end; |
|||
in |
|||
m := loop (hashtbl_make_nil<key, a> (i2sz 1024), |
|||
i2sz 0, i2sz 0) |
|||
end |
|||
implement (* A demonstration. *) |
|||
main0 () = |
|||
let |
|||
val src = |
|||
arrayref_make_list<string> |
|||
(10, $list ("a", "c", "b", "e", "a", |
|||
"a", "d", "d", "b", "c")) |
|||
val dst = arrayref_make_elt<string> (i2sz 10, "?") |
|||
var m : size_t |
|||
in |
|||
remove_dups<string, string> (lam s => s, src, i2sz 10, dst, m); |
|||
let |
|||
prval [m : int] EQINT () = eqint_make_guint m |
|||
var i : natLte m |
|||
in |
|||
for (i := 0; i2sz i <> m; i := succ i) |
|||
print! (" ", dst[i]); |
|||
println! () |
|||
end |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> a c b e d</pre> |
|||
=== ATS2 implementation for values containing a mutable ''seen'' flag === |
|||
This method runs O(n) in the number of elements. It can be useful when you are working with references to complicated data structures. It works only if the array contains references to structures, rather than the structures themselves. |
|||
This implementation is for non-linear types only and happens to demonstrate "ordinary" imperative programming in ATS2: without dependent types, proofs, etc. The code is still safe against over-running array boundaries, but the safety is enforced by run-time checks rather than proofs. |
|||
<syntaxhighlight lang="ats"> |
|||
(* Remove duplicate elements. |
|||
This implementation is for elements that contain a "this has been |
|||
seen" flag. It is O(n) in the number of elements. |
|||
Also, this implementation demonstrates that imperative programming, |
|||
without dependent types or proofs, is possible in ATS. *) |
|||
#include "share/atspre_staload.hats" |
|||
(* A tuple in the heap. *) |
|||
typedef seen_or_not (a : t@ype+) = '(a, ref bool) |
|||
(* How the remove_dups function will be called. *) |
|||
extern fn {a : t@ype} |
|||
remove_dups |
|||
(given_data : arrszref (seen_or_not a), |
|||
space_for_result : arrszref (seen_or_not a), |
|||
num_of_unique_elems : &size_t? >> size_t) |
|||
: void |
|||
implement {a} |
|||
remove_dups (given_data, space_for_result, num_of_unique_elems) = |
|||
let |
|||
macdef seen (i) = given_data[,(i)].1 |
|||
var i : size_t |
|||
var j : size_t |
|||
in |
|||
(* Clear all the "seen" flags. *) |
|||
for (i := i2sz 0; i <> size given_data; i := succ i) |
|||
!(seen i) := false; |
|||
(* Loop through given_data, copying (pointers to) any values that |
|||
have not yet been seen. *) |
|||
j := i2sz 0; |
|||
for (i := i2sz 0; i <> size given_data; i := succ i) |
|||
if !(seen i) then |
|||
() (* Skip any element that has already been seen. *) |
|||
else |
|||
begin |
|||
!(seen i) := true; (* Mark the element as seen. *) |
|||
space_for_result[j] := given_data[i]; |
|||
j := succ j |
|||
end; |
|||
num_of_unique_elems := j |
|||
end |
|||
implement (* A demonstration. *) |
|||
main0 () = |
|||
let |
|||
(* Define some values. *) |
|||
val a = '("a", ref<bool> false) |
|||
val b = '("b", ref<bool> false) |
|||
val c = '("c", ref<bool> false) |
|||
val d = '("d", ref<bool> false) |
|||
val e = '("e", ref<bool> false) |
|||
(* Fill an array with values. *) |
|||
val data = |
|||
arrszref_make_list ($list (a, c, b, e, a, a, d, d, b, c)) |
|||
(* Allocate storage for the result. *) |
|||
val unique_elems = arrszref_make_elt (i2sz 10, a) |
|||
var num_of_unique_elems : size_t |
|||
var i : size_t |
|||
in |
|||
(* Remove duplicates. *) |
|||
remove_dups<string> (data, unique_elems, num_of_unique_elems); |
|||
(* Print the results. *) |
|||
for (i := i2sz 0; i <> num_of_unique_elems; i := succ i) |
|||
print! (" ", unique_elems[i].0); |
|||
println! () |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> a c b e d</pre> |
|||
=={{header|AutoHotkey}}== |
|||
Built in Sort has an option to remove duplicates |
|||
<syntaxhighlight lang="autohotkey">a = 1,2,1,4,5,2,15,1,3,4 |
|||
Sort, a, a, NUD`, |
|||
MsgBox % a ; 1,2,3,4,5,15</syntaxhighlight> |
|||
=={{header|AWK}}== |
|||
We produce an array a with duplicates from a string; |
|||
then index a second array b with the contents of a, |
|||
so that duplicates make only one entry; |
|||
then produce a string with the keys of b, |
|||
which is finally output. |
|||
<syntaxhighlight lang="awk">$ awk 'BEGIN{split("a b c d c b a",a);for(i in a)b[a[i]]=1;r="";for(i in b)r=r" "i;print r}' |
|||
a b c d</syntaxhighlight> |
|||
=={{header|BASIC}}== |
|||
==={{header|ANSI BASIC}}=== |
|||
{{trans|Modula-2}} |
|||
{{works with|Decimal BASIC}} |
|||
<syntaxhighlight lang="basic"> |
|||
100 REM Remove duplicate elements |
|||
110 DIM DataArray(1 TO 7), ResultArray(1 TO 7) |
|||
120 ! Set the data. |
|||
130 FOR I = 1 TO 7 |
|||
140 READ DataArray(I) |
|||
150 NEXT I |
|||
160 ! Remove duplicates |
|||
170 LET ResultArray(1) = DataArray(1) |
|||
180 LET LastResultIndex = 1 |
|||
190 LET Position = 1 |
|||
200 DO WHILE Position < UBOUND(DataArray) |
|||
210 LET Position = Position + 1 |
|||
220 LET IsNewNumber = -1 |
|||
230 FOR ResultIndex = 1 TO LastResultIndex |
|||
240 IF DataArray(Position) = ResultArray(ResultIndex) THEN |
|||
250 LET IsNewNumber = 0 |
|||
260 EXIT FOR |
|||
270 END IF |
|||
280 NEXT ResultIndex |
|||
290 IF IsNewNumber = -1 THEN |
|||
300 LET LastResultIndex = LastResultIndex + 1 |
|||
310 LET ResultArray(LastResultIndex) = DataArray(Position) |
|||
320 END IF |
|||
330 LOOP |
|||
340 FOR ResultIndex = 1 TO LastResultIndex |
|||
350 PRINT ResultArray(ResultIndex) |
|||
360 NEXT ResultIndex |
|||
370 DATA 1, 2, 2, 3, 4, 5, 5 |
|||
380 END |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
</pre> |
|||
=={{header|Applesoft BASIC}}== |
==={{header|Applesoft BASIC}}=== |
||
< |
<syntaxhighlight lang="basic">100 DIM L$(15) |
||
110 L$(0) = "NOW" |
110 L$(0) = "NOW" |
||
120 L$(1) = "IS" |
120 L$(1) = "IS" |
||
Line 413: | Line 1,576: | ||
520 L$(N) = "" |
520 L$(N) = "" |
||
530 N = N - 1 |
530 N = N - 1 |
||
540 RETURN</ |
540 RETURN</syntaxhighlight> |
||
=={{header| |
==={{header|BASIC256}}=== |
||
{{trans|True BASIC}} |
|||
<syntaxhighlight lang="basic256"> |
|||
arraybase 1 |
|||
max = 10 |
|||
dim res(max) |
|||
dim dat(max) |
|||
dat[1] = 1: dat[2] = 2: dat[3] = 1: dat[4] = 4: dat[5] = 5 |
|||
dat[6] = 2: dat[7] = 15: dat[8] = 1: dat[9] = 3: dat[10] = 4 |
|||
res[1] = dat[1] |
|||
cont = 1 |
|||
<lang rebol>arr: [1 2 3 2 1 2 3 4 5 3 2 1] |
|||
posic = 1 |
|||
while posic < max |
|||
print unique arr</lang> |
|||
posic += 1 |
|||
esnuevo = 1 |
|||
indice = 1 |
|||
while indice <= cont and esnuevo = 1 |
|||
if dat[posic] = res[indice] then esnuevo = 0 |
|||
indice += 1 |
|||
end while |
|||
if esnuevo = 1 then |
|||
cont += 1 |
|||
res[cont] = dat[posic] |
|||
end if |
|||
end while |
|||
for i = 1 to cont |
|||
{{out}} |
|||
print res[i]; " "; |
|||
next i |
|||
end |
|||
</syntaxhighlight> |
|||
==={{header|BBC BASIC}}=== |
|||
<pre>1 2 3 4 5</pre> |
|||
=={{header|AutoHotkey}}== |
|||
Built in Sort has an option to remove duplicates |
|||
<lang AutoHotkey>a = 1,2,1,4,5,2,15,1,3,4 |
|||
Sort, a, a, NUD`, |
|||
MsgBox % a ; 1,2,3,4,5,15</lang> |
|||
=={{header|AWK}}== |
|||
We produce an array a with duplicates from a string; |
|||
then index a second array b with the contents of a, |
|||
so that duplicates make only one entry; |
|||
then produce a string with the keys of b, |
|||
which is finally output. |
|||
<lang awk>$ awk 'BEGIN{split("a b c d c b a",a);for(i in a)b[a[i]]=1;r="";for(i in b)r=r" "i;print r}' |
|||
a b c d</lang> |
|||
=={{header|BBC BASIC}}== |
|||
{{works with|BBC BASIC for Windows}} |
{{works with|BBC BASIC for Windows}} |
||
< |
<syntaxhighlight lang="bbcbasic"> DIM list$(15) |
||
list$() = "Now", "is", "the", "time", "for", "all", "good", "men", \ |
list$() = "Now", "is", "the", "time", "for", "all", "good", "men", \ |
||
\ "to", "come", "to", "the", "aid", "of", "the", "party." |
\ "to", "come", "to", "the", "aid", "of", "the", "party." |
||
Line 462: | Line 1,633: | ||
IF j%>=i% l$(n%) = i$ : n% += 1 |
IF j%>=i% l$(n%) = i$ : n% += 1 |
||
NEXT |
NEXT |
||
= n%</ |
= n%</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Now is the time for all good men to come aid of party. |
Now is the time for all good men to come aid of party. |
||
</pre> |
</pre> |
||
==={{header|FreeBASIC}}=== |
|||
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64 |
|||
Sub removeDuplicates(a() As Integer, b() As Integer) |
|||
Dim lb As Integer = LBound(a) |
|||
Dim ub As Integer = UBound(a) |
|||
If ub = -1 Then Return '' empty array |
|||
Redim b(lb To ub) |
|||
b(lb) = a(lb) |
|||
Dim count As Integer = 1 |
|||
Dim unique As Boolean |
|||
For i As Integer = lb + 1 To ub |
|||
unique = True |
|||
For j As Integer = lb to i - 1 |
|||
If a(i) = a(j) Then |
|||
unique = False |
|||
Exit For |
|||
End If |
|||
Next j |
|||
If unique Then |
|||
b(lb + count) = a(i) |
|||
count += 1 |
|||
End If |
|||
Next i |
|||
If count > 0 Then Redim Preserve b(lb To lb + count - 1) |
|||
End Sub |
|||
Dim a(1 To 10) As Integer = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4} |
|||
Dim b() As Integer |
|||
removeDuplicates a(), b() |
|||
For i As Integer = LBound(b) To UBound(b) |
|||
Print b(i); " "; |
|||
Next |
|||
Print |
|||
Print "Press any key to quit" |
|||
Sleep</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 2 4 5 15 3 |
|||
</pre> |
|||
==={{header|FutureBasic}}=== |
|||
<syntaxhighlight lang="futurebasic"> |
|||
include "NSLog.incl" |
|||
CFArrayRef array, unique |
|||
OrderedSetRef ordered |
|||
array = @[@"A", @"B", @"C", @"B", @"A", @"C", @"A", @"C", @"A", @"B", @"C"] |
|||
ordered = fn OrderedSetWithArray( array ) |
|||
NSLog( @"%@", fn OrderedSetArray( ordered ) ) |
|||
HandleEvents |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
<pre> |
|||
( |
|||
A, |
|||
B, |
|||
C |
|||
) |
|||
</pre> |
|||
==={{header|Gambas}}=== |
|||
'''[https://gambas-playground.proko.eu/?gist=1e2bb524d2278cd88bccdc21a1683296 Click this link to run this code]''' |
|||
<syntaxhighlight lang="gambas">Public Sub Main() |
|||
Dim sString As String[] = Split("Now is the time for all the good men to come to the aid of the good party 1 2 1 3 3 3 2 1 1 2 3 4 33 2 5 4 333 5", " ") |
|||
Dim sFix As New String[] |
|||
Dim sTemp As String |
|||
For Each sTemp In sString |
|||
sTemp &= " " |
|||
If InStr(sFix.Join(" ") & " ", sTemp) Then Continue |
|||
sFix.Add(Trim(sTemp)) |
|||
Next |
|||
Print sFix.Join(" ") |
|||
End</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
Now is the time for all good men to come aid of party 1 2 3 4 33 5 333 |
|||
</pre> |
|||
==={{header|GW-BASIC}}=== |
|||
{{trans|Modula-2}} |
|||
{{works with|BASICA}} |
|||
{{works with|PC-BASIC|any}} |
|||
<syntaxhighlight lang="qbasic"> |
|||
10 ' Remove Duplicates |
|||
20 OPTION BASE 1 |
|||
30 LET MAXI% = 7 |
|||
40 DIM D(7), R(7): ' data, result |
|||
50 ' Set the data. |
|||
60 FOR I% = 1 TO 7 |
|||
70 READ D(I%) |
|||
80 NEXT I% |
|||
90 ' Remove duplicates. |
|||
100 LET R(1) = D(1) |
|||
110 LET LRI% = 1: ' last index of result |
|||
120 LET P% = 1: ' position |
|||
130 WHILE P% < MAXI% |
|||
140 LET P% = P% + 1 |
|||
150 LET ISNEW = 1: ' is a new number? |
|||
160 LET RI% = 1: ' current index of result |
|||
170 WHILE (RI% <= LRI%) AND ISNEW |
|||
180 IF D(P%) = R(RI%) THEN LET ISNEW = 0 |
|||
190 LET RI% = RI% + 1 |
|||
200 WEND |
|||
210 IF ISNEW THEN LET LRI% = LRI% + 1: LET R(LRI%) = D(P%) |
|||
220 WEND |
|||
230 FOR RI% = 1 TO LRI% |
|||
240 PRINT R(RI%) |
|||
250 NEXT RI% |
|||
260 END |
|||
1000 DATA 1, 2, 2, 3, 4, 5, 5 |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
</pre> |
|||
==={{header|IS-BASIC}}=== |
|||
<syntaxhighlight lang="is-basic">100 PROGRAM "RemoveDu.bas" |
|||
110 RANDOMIZE |
|||
120 NUMERIC ARR(1 TO 20),TOP |
|||
130 LET TOP=FILL(ARR) |
|||
140 CALL WRITE(ARR,TOP) |
|||
150 LET TOP=REMOVE(ARR) |
|||
160 CALL WRITE(ARR,TOP) |
|||
170 DEF WRITE(REF A,N) |
|||
180 FOR I=1 TO N |
|||
190 PRINT A(I); |
|||
200 NEXT |
|||
210 PRINT |
|||
220 END DEF |
|||
230 DEF FILL(REF A) |
|||
240 LET FILL=UBOUND(A):LET A(LBOUND(A))=1 |
|||
250 FOR I=LBOUND(A)+1 TO UBOUND(A) |
|||
260 LET A(I)=A(I-1)+RND(3) |
|||
270 NEXT |
|||
280 END DEF |
|||
290 DEF REMOVE(REF A) |
|||
300 LET ST=0 |
|||
310 FOR I=LBOUND(A)+1 TO UBOUND(A) |
|||
320 IF A(I-1)=A(I) THEN LET ST=ST+1 |
|||
330 IF ST>0 THEN LET A(I-ST)=A(I) |
|||
340 NEXT |
|||
350 LET REMOVE=UBOUND(A)-ST |
|||
360 END DEF</syntaxhighlight> |
|||
{{out}} |
|||
<pre>START |
|||
1 1 2 4 5 7 9 10 12 14 16 16 16 17 18 20 20 22 23 23 |
|||
1 2 4 5 7 9 10 12 14 16 17 18 20 22 23 |
|||
ok |
|||
START |
|||
1 2 4 5 5 5 7 8 9 9 10 10 10 12 14 15 17 17 18 20 |
|||
1 2 4 5 7 8 9 10 12 14 15 17 18 20 |
|||
ok |
|||
START |
|||
1 3 3 4 5 6 8 10 11 12 14 16 16 16 16 18 18 19 21 21 |
|||
1 3 4 5 6 8 10 11 12 14 16 18 19 21 |
|||
ok |
|||
START |
|||
1 3 3 4 5 5 7 9 11 13 13 14 16 17 17 18 19 19 20 21 |
|||
1 3 4 5 7 9 11 13 14 16 17 18 19 20 21 |
|||
ok |
|||
START |
|||
1 2 3 5 5 6 6 7 8 10 12 14 15 17 17 19 21 23 25 25 |
|||
1 2 3 5 6 7 8 10 12 14 15 17 19 21 23 25 |
|||
ok</pre> |
|||
==={{header|Liberty BASIC}}=== |
|||
LB has arrays, but here the elements are stored in a space-separated string. |
|||
{{works sith|Just BASIC}} |
|||
<syntaxhighlight lang="lb"> |
|||
a$ =" 1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19 " |
|||
print "Original set of elements = ["; a$; "]" |
|||
b$ =removeDuplicates$( a$) |
|||
print "With duplicates removed = ["; b$; "]" |
|||
end |
|||
function removeDuplicates$( in$) |
|||
o$ =" " |
|||
i =1 |
|||
do |
|||
term$ =word$( in$, i, " ") |
|||
if instr( o$, " "; term$; " ") =0 and term$ <>" " then o$ =o$ +term$ +" " |
|||
i =i +1 |
|||
loop until term$ ="" |
|||
removeDuplicates$ =o$ |
|||
end function |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Original set of elements = [ 1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19 ] |
|||
With duplicates removed = [ 1 $23.19 2 elbow 3 Bork 4 ] |
|||
</pre> |
|||
==={{header|Microsoft Small Basic}}=== |
|||
{{trans|Modula-2}} |
|||
<syntaxhighlight lang="microsoftsmallbasic"> |
|||
' Set the data. |
|||
dataArray[1] = 1 |
|||
dataArray[2] = 2 |
|||
dataArray[3] = 2 |
|||
dataArray[4] = 3 |
|||
dataArray[5] = 4 |
|||
dataArray[6] = 5 |
|||
dataArray[7] = 5 |
|||
resultArray[1] = dataArray[1] |
|||
lastResultIndex = 1 |
|||
position = 1 |
|||
While position < Array.GetItemCount(dataArray) |
|||
position = position + 1 |
|||
isNewNumber = 1 ' logical 1 |
|||
resultIndex = 1 |
|||
While (resultIndex <= lastResultIndex) And isNewNumber = 1 |
|||
If dataArray[position] = resultArray[resultIndex] Then |
|||
isNewNumber = 0 |
|||
EndIf |
|||
resultIndex = resultIndex + 1 |
|||
EndWhile |
|||
If isNewNumber = 1 Then |
|||
lastResultIndex = lastResultIndex + 1 |
|||
resultArray[lastResultIndex] = dataArray[position] |
|||
EndIf |
|||
EndWhile |
|||
For resultIndex = 1 To lastResultIndex |
|||
TextWindow.WriteLine(resultArray[resultIndex]) |
|||
EndFor |
|||
</syntaxhighlight> |
|||
==={{header|PureBasic}}=== |
|||
Task solved with the built in Hash Table which are called Maps in PureBasic |
|||
<syntaxhighlight lang="purebasic">NewMap MyElements.s() |
|||
For i=0 To 9 ;Mark 10 items at random, causing high risk of duplication items. |
|||
x=Random(9) |
|||
t$="Number "+str(x)+" is marked" |
|||
MyElements(str(x))=t$ ; Add element 'X' to the hash list or overwrite if already included. |
|||
Next |
|||
ForEach MyElements() |
|||
Debug MyElements() |
|||
Next</syntaxhighlight> |
|||
Output may look like this, e.g. duplicated items are automatically removed as they have the same hash value. |
|||
Number 0 is marked |
|||
Number 2 is marked |
|||
Number 5 is marked |
|||
Number 6 is marked |
|||
==={{header|Run BASIC}}=== |
|||
<syntaxhighlight lang="runbasic">a$ = "2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2" |
|||
for i = 1 to len(a$) |
|||
a1$ = word$(a$,i) |
|||
if a1$ = "" then exit for |
|||
for i1 = 1 to len(b$) |
|||
if a1$ = word$(b$,i1) then [nextWord] |
|||
next i1 |
|||
b$ = b$ + a1$ + " " |
|||
[nextWord] |
|||
next i |
|||
print "Dups:";a$ |
|||
print "No Dups:";b$</syntaxhighlight> |
|||
<pre>Dups:2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2 |
|||
No Dups:2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 0 4.4 </pre> |
|||
==={{header|True BASIC}}=== |
|||
{{trans|GW-BASIC}} |
|||
{{works with|QBasic}} |
|||
{{works with|Decimal BASIC}} |
|||
<syntaxhighlight lang="basic"> |
|||
OPTION BASE 1 |
|||
LET max = 10 |
|||
DIM dat(10), res(10) |
|||
FOR i = 1 TO max |
|||
READ dat(i) |
|||
NEXT i |
|||
DATA 1, 2, 1, 4, 5, 2, 15, 1, 3, 4 |
|||
LET res(1) = dat(1) |
|||
LET count = 1 |
|||
LET posic = 1 |
|||
DO WHILE posic < max |
|||
LET posic = posic + 1 |
|||
LET esnuevo = 1 |
|||
LET indice = 1 |
|||
DO WHILE (indice <= count) AND esnuevo = 1 |
|||
IF dat(posic) = res(indice) THEN LET esnuevo = 0 |
|||
LET indice = indice + 1 |
|||
LOOP |
|||
IF esnuevo = 1 THEN |
|||
LET count = count + 1 |
|||
LET res(count) = dat(posic) |
|||
END IF |
|||
LOOP |
|||
FOR i = 1 TO count |
|||
PRINT res(i); |
|||
NEXT i |
|||
END |
|||
</syntaxhighlight> |
|||
==={{header|VBA}}=== |
|||
Hash Table Approach |
|||
Input list (variant : Long, Double, Boolean and Strings) : |
|||
Array(1.23456789101112E+16, True, False, True, "Alpha", 1, 235, 4, 1.25, 1.25, "Beta", 1.23456789101112E+16, "Delta", "Alpha", "Charlie", 1, 2, "Foxtrot", "Foxtrot", "Alpha", 235) |
|||
<syntaxhighlight lang="vb"> |
|||
Option Explicit |
|||
Sub Main() |
|||
Dim myArr() As Variant, i As Long |
|||
myArr = Remove_Duplicate(Array(1.23456789101112E+16, True, False, True, "Alpha", 1, 235, 4, 1.25, 1.25, "Beta", 1.23456789101112E+16, "Delta", "Alpha", "Charlie", 1, 2, "Foxtrot", "Foxtrot", "Alpha", 235)) |
|||
'return : |
|||
For i = LBound(myArr) To UBound(myArr) |
|||
Debug.Print myArr(i) |
|||
Next |
|||
End Sub |
|||
Private Function Remove_Duplicate(Arr As Variant) As Variant() |
|||
Dim myColl As New Collection, Temp() As Variant, i As Long, cpt As Long |
|||
ReDim Temp(UBound(Arr)) |
|||
For i = LBound(Arr) To UBound(Arr) |
|||
On Error Resume Next |
|||
myColl.Add CStr(Arr(i)), CStr(Arr(i)) |
|||
If Err.Number > 0 Then |
|||
On Error GoTo 0 |
|||
Else |
|||
Temp(cpt) = Arr(i) |
|||
cpt = cpt + 1 |
|||
End If |
|||
Next i |
|||
ReDim Preserve Temp(cpt - 1) |
|||
Remove_Duplicate = Temp |
|||
End Function</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1.23456789101112E+16 |
|||
True |
|||
False |
|||
Alpha |
|||
1 |
|||
235 |
|||
4 |
|||
1.25 |
|||
Beta |
|||
Delta |
|||
Charlie |
|||
2 |
|||
Foxtrot</pre> |
|||
==={{header|VBScript}}=== |
|||
Hash Table Approach |
|||
<syntaxhighlight lang="vb"> |
|||
Function remove_duplicates(list) |
|||
arr = Split(list,",") |
|||
Set dict = CreateObject("Scripting.Dictionary") |
|||
For i = 0 To UBound(arr) |
|||
If dict.Exists(arr(i)) = False Then |
|||
dict.Add arr(i),"" |
|||
End If |
|||
Next |
|||
For Each key In dict.Keys |
|||
tmp = tmp & key & "," |
|||
Next |
|||
remove_duplicates = Left(tmp,Len(tmp)-1) |
|||
End Function |
|||
WScript.Echo remove_duplicates("a,a,b,b,c,d,e,d,f,f,f,g,h") |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>a,b,c,d,e,f,g,h</pre> |
|||
==={{header|Yabasic}}=== |
|||
<syntaxhighlight lang="yabasic">data "Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "to", "the", "aid", "of", "the", "party.", "" |
|||
do |
|||
read p$ |
|||
if p$ = "" break |
|||
if not instr(r$, p$) r$ = r$ + p$ + " " |
|||
loop |
|||
print r$</syntaxhighlight> |
|||
=={{header|BQN}}== |
|||
<syntaxhighlight lang="bqn">⍷ 2‿4‿9‿7‿3‿7‿4‿1‿9‿2‿5‿7‿2‿2‿8‿9‿6‿6‿5‿8</syntaxhighlight> |
|||
{{out}} |
|||
<pre>⟨ 2 4 9 7 3 1 5 8 6 ⟩</pre> |
|||
=={{header|Bracmat}}== |
=={{header|Bracmat}}== |
||
Line 472: | Line 2,047: | ||
The list contains atoms and also a few non-atomic expressions. The hash table needs atomic keys, so we apply the <code>str</code> function when searching and inserting elements. |
The list contains atoms and also a few non-atomic expressions. The hash table needs atomic keys, so we apply the <code>str</code> function when searching and inserting elements. |
||
< |
<syntaxhighlight lang="bracmat">2 3 5 7 11 13 17 19 cats 222 (-100.2) "+11" (1.1) "+7" (7.) 7 5 5 3 2 0 (4.4) 2:?LIST |
||
(A= |
(A= |
||
Line 534: | Line 2,109: | ||
& !C |
& !C |
||
& |
& |
||
)</ |
)</syntaxhighlight> |
||
Only solution B produces a list with the same order of elements as in the input. |
Only solution B produces a list with the same order of elements as in the input. |
||
<pre>Solution A: 19 (4.4) 17 11 13 (1.1) (7.) 222 +11 7 5 3 2 0 cats (-100.2) +7 |
<pre>Solution A: 19 (4.4) 17 11 13 (1.1) (7.) 222 +11 7 5 3 2 0 cats (-100.2) +7 |
||
Line 541: | Line 2,116: | ||
=={{header|Brat}}== |
=={{header|Brat}}== |
||
< |
<syntaxhighlight lang="brat">some_array = [1 1 2 1 'redundant' [1 2 3] [1 2 3] 'redundant'] |
||
unique_array = some_array.unique</ |
unique_array = some_array.unique</syntaxhighlight> |
||
=={{header|C}}== |
=={{header|C}}== |
||
Line 551: | Line 2,126: | ||
Since there's no way to know ahead of time how large the new data structure will need to be, we'll return a linked list instead of an array. |
Since there's no way to know ahead of time how large the new data structure will need to be, we'll return a linked list instead of an array. |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
Line 583: | Line 2,158: | ||
printf("%d ", n->x); |
printf("%d ", n->x); |
||
puts(""); |
puts(""); |
||
return 0;}</ |
return 0;}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 590: | Line 2,165: | ||
===O(n^2) version, pure arrays=== |
===O(n^2) version, pure arrays=== |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <stdbool.h> |
#include <stdbool.h> |
||
Line 648: | Line 2,223: | ||
free(b); |
free(b); |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 655: | Line 2,230: | ||
===Sorting method=== |
===Sorting method=== |
||
Using qsort and return uniques in-place:< |
Using qsort and return uniques in-place:<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
Line 683: | Line 2,258: | ||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 695: | Line 2,270: | ||
=={{header|C sharp}}== |
=={{header|C sharp}}== |
||
{{works with |C sharp|C#|2+}} |
{{works with |C sharp|C#|2+}} |
||
< |
<syntaxhighlight lang="csharp">int[] nums = { 1, 1, 2, 3, 4, 4 }; |
||
List<int> unique = new List<int>(); |
List<int> unique = new List<int>(); |
||
foreach (int n in nums) |
foreach (int n in nums) |
||
if (!unique.Contains(n)) |
if (!unique.Contains(n)) |
||
unique.Add(n);</ |
unique.Add(n);</syntaxhighlight> |
||
{{works with |C sharp|C#|3+}} |
{{works with |C sharp|C#|3+}} |
||
< |
<syntaxhighlight lang="csharp">int[] nums = {1, 1, 2, 3, 4, 4}; |
||
int[] unique = nums.Distinct().ToArray();</ |
int[] unique = nums.Distinct().ToArray();</syntaxhighlight> |
||
=={{header|C++}}== |
=={{header|C++}}== |
||
This version uses <tt>std::set</tt>, which requires its element type be comparable using the < operator. |
This version uses <tt>std::set</tt>, which requires its element type be comparable using the < operator. |
||
< |
<syntaxhighlight lang="cpp">#include <set> |
||
#include <iostream> |
#include <iostream> |
||
using namespace std; |
using namespace std; |
||
Line 721: | Line 2,296: | ||
cout << *iter << " "; |
cout << *iter << " "; |
||
cout << endl; |
cout << endl; |
||
}</ |
}</syntaxhighlight> |
||
This version uses <tt>hash_set</tt>, which is part of the SGI extension to the Standard Template Library. It is not part of the C++ standard library. It requires that its element type have a hash function. |
This version uses <tt>hash_set</tt>, which is part of the SGI extension to the Standard Template Library. It is not part of the C++ standard library. It requires that its element type have a hash function. |
||
{{works with|GCC}} |
{{works with|GCC}} |
||
< |
<syntaxhighlight lang="cpp">#include <ext/hash_set> |
||
#include <iostream> |
#include <iostream> |
||
using namespace std; |
using namespace std; |
||
Line 740: | Line 2,315: | ||
cout << *iter << " "; |
cout << *iter << " "; |
||
cout << endl; |
cout << endl; |
||
}</ |
}</syntaxhighlight> |
||
This version uses <tt>unordered_set</tt>, which is part of the TR1, which is likely to be included in the next version of C++. It is not part of the C++ standard library. It requires that its element type have a hash function. |
This version uses <tt>unordered_set</tt>, which is part of the TR1, which is likely to be included in the next version of C++. It is not part of the C++ standard library. It requires that its element type have a hash function. |
||
{{works with|GCC}} |
{{works with|GCC}} |
||
< |
<syntaxhighlight lang="cpp">#include <tr1/unordered_set> |
||
#include <iostream> |
#include <iostream> |
||
using namespace std; |
using namespace std; |
||
Line 759: | Line 2,334: | ||
cout << *iter << " "; |
cout << *iter << " "; |
||
cout << endl; |
cout << endl; |
||
}</ |
}</syntaxhighlight> |
||
Alternative method working directly on the array: |
Alternative method working directly on the array: |
||
< |
<syntaxhighlight lang="cpp">#include <iostream> |
||
#include <iterator> |
#include <iterator> |
||
#include <algorithm> |
#include <algorithm> |
||
Line 777: | Line 2,352: | ||
std::copy(data, new_end, std::ostream_iterator<int>(std::cout, " "); |
std::copy(data, new_end, std::ostream_iterator<int>(std::cout, " "); |
||
std::cout << std::endl; |
std::cout << std::endl; |
||
}</ |
}</syntaxhighlight> |
||
Using sort, unique, and erase on a vector. |
Using sort, unique, and erase on a vector. |
||
{{works with|C++11}} |
{{works with|C++11}} |
||
< |
<syntaxhighlight lang="cpp">#include <algorithm> |
||
#include <iostream> |
#include <iostream> |
||
#include <vector> |
#include <vector> |
||
Line 794: | Line 2,369: | ||
std::cout << std::endl; |
std::cout << std::endl; |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|CafeOBJ}}== |
=={{header|CafeOBJ}}== |
||
The parametrized module NO-DUP-LIST(ELEMENTS :: TRIV) defines the signature of a space separated list structure. The removal of duplicates is handled by the equational properties listed after the signature in brackets {}. There is no user written code in module NO-DUP-LIST. The binary operation (_ _) is associative, commutative, and idempotent, meaning (x , x) = x. This list structure does not permit duplicates, they are removed during evaluation (called reduction in CafeOBJ). Using this module we can perform set union, just by evaluating two lists e.g: |
|||
<lang CafeOBJ> |
|||
<syntaxhighlight lang="$CafeOBJ"> |
|||
-- The parametrized module NO-DUP-LIST(ELEMENTS :: TRIV) defines the signature of simple Haskell like list structure. |
|||
red (1 2 3 4) (3 2 1 5) . |
|||
-- The removal of duplicates is handled by the equational properties listed after the signature in brackets {} |
|||
--> (4 5 1 2 3):Int |
|||
-- The binary operation _,_ is associative, commutative, and idempotent. |
|||
</syntaxhighlight> |
|||
-- This list structure does not permit duplicates, they are removed during evaluation (called reduction in CafeOBJ) |
|||
-- Actual code is contained in module called NO-DUP-LIST. |
|||
-- The tests are performed after opening instantiated NO-DUP-LIST with various concrete types. |
|||
-- For further details see: http://www.ldl.jaist.ac.jp/cafeobj/ |
|||
<syntaxhighlight lang="$CafeOBJ"> |
|||
mod! NO-DUP-LIST(ELEMENTS :: TRIV) { |
mod! NO-DUP-LIST(ELEMENTS :: TRIV) { |
||
op __ : Elt Elt -> Elt { comm assoc idem assoc } |
|||
op [] : -> List { prec: 0 } -- Empty List |
|||
op _,_ : Elt Elt -> Elt { comm assoc idem prec: 80 l-assoc } |
|||
op [_] : Elt -> List { prec: 0 } |
|||
} |
} |
||
-- Runs on Version 1.5.1(PigNose0.99) of CafeOBJ |
|||
-- Test on lists of INT, CHARACTER, and STRING |
|||
-- The tests are performed after opening instantiated NO-DUP-LIST with various concrete types. |
|||
open NO-DUP-LIST(INT) |
|||
-- Test on lists of INT |
|||
reduce [ 1 , 2 , 1 , 1 ] . -- Gives [ 1 , 2 ] |
|||
open NO-DUP-LIST( |
open NO-DUP-LIST(INT) . |
||
red 2 1 2 1 2 1 3 . |
|||
-- Gives (2 1 3):Int |
|||
open NO-DUP-LIST(STRING) |
|||
open NO-DUP-LIST(INT) . |
|||
reduce [ "abc" , "def" , "abc" ] . -- Gives [ "def" , "abc" ] |
|||
reduce 1 1 2 1 1 . |
|||
</lang> |
|||
close |
|||
open NO-DUP-LIST(CHARACTER) . |
|||
reduce 'a' 'b' 'a' 'a' . |
|||
close |
|||
open NO-DUP-LIST(STRING) . |
|||
reduce "abc" "def" "abc" "abc" "abc" . |
|||
close |
|||
</syntaxhighlight> |
|||
'''How does work?''' |
|||
The evaluation automatically uses right associativity. So starting with: |
|||
<pre> (1 1 2 1 1)</pre> |
|||
The system places appropriate brackets on the entire expression: |
|||
<pre> (1 ((1 2) (1 1))) </pre> |
|||
Idempotency is applied at rightmost inner brackets: |
|||
We get rewrite ''(1 1) -> 1''. The term is now: |
|||
<pre> (1 ((1 2) 1)) </pre> |
|||
Any further occurrence of 1 will be removed. |
|||
Idempotency is applied at inner brackets ''(1 2) ''. |
|||
We get rewrite ''(1 2) -> 2 ''. The term is now: |
|||
<pre>(1 (2 1))</pre> |
|||
By already established idempotency we finally get |
|||
<pre>(2 1)</pre> |
|||
=={{header|Ceylon}}== |
=={{header|Ceylon}}== |
||
< |
<syntaxhighlight lang="ceylon"><String|Integer>[] data = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"]; |
||
<String|Integer>[] unique = HashSet { *data }.sequence();</ |
<String|Integer>[] unique = HashSet { *data }.sequence();</syntaxhighlight> |
||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
< |
<syntaxhighlight lang="lisp">user=> (distinct [1 3 2 9 1 2 3 8 8 1 0 2]) |
||
(1 3 2 9 8 0) |
(1 3 2 9 8 0) |
||
user=></ |
user=></syntaxhighlight> |
||
=={{header|CoffeeScript}}== |
=={{header|CoffeeScript}}== |
||
{{trans|Kotlin}} |
{{trans|Kotlin}} |
||
< |
<syntaxhighlight lang="coffeescript">data = [ 1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d" ] |
||
set = [] |
set = [] |
||
set.push i for i in data when not (i in set) |
set.push i for i in data when not (i in set) |
||
console.log data |
console.log data |
||
console.log set</ |
console.log set</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[ 1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd' ] |
<pre>[ 1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd' ] |
||
Line 847: | Line 2,455: | ||
To remove duplicates non-destructively: |
To remove duplicates non-destructively: |
||
< |
<syntaxhighlight lang="lisp">(remove-duplicates '(1 3 2 9 1 2 3 8 8 1 0 2)) |
||
> (9 3 8 1 0 2)</ |
> (9 3 8 1 0 2)</syntaxhighlight> |
||
Or, to remove duplicates in-place: |
Or, to remove duplicates in-place: |
||
< |
<syntaxhighlight lang="lisp">(delete-duplicates '(1 3 2 9 1 2 3 8 8 1 0 2)) |
||
> (9 3 8 1 0 2)</ |
> (9 3 8 1 0 2)</syntaxhighlight> |
||
=={{header|Crystal}}== |
=={{header|Crystal}}== |
||
Line 859: | Line 2,467: | ||
Copied and modified from the Ruby version. |
Copied and modified from the Ruby version. |
||
< |
<syntaxhighlight lang="ruby">ary = [1, 1, 2, 2, "a", [1, 2, 3], [1, 2, 3], "a"] |
||
p ary.uniq</ |
p ary.uniq</syntaxhighlight> |
||
<pre>[1, 2, "a", [1, 2, 3]]</pre> |
<pre>[1, 2, "a", [1, 2, 3]]</pre> |
||
=={{header|D}}== |
=={{header|D}}== |
||
< |
<syntaxhighlight lang="d">void main() { |
||
import std.stdio, std.algorithm; |
import std.stdio, std.algorithm; |
||
Line 872: | Line 2,480: | ||
.uniq |
.uniq |
||
.writeln; |
.writeln; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[0, 1, 2, 3, 8, 9]</pre> |
<pre>[0, 1, 2, 3, 8, 9]</pre> |
||
Using an associative array: |
Using an associative array: |
||
< |
<syntaxhighlight lang="d">void main() { |
||
import std.stdio; |
import std.stdio; |
||
Line 885: | Line 2,493: | ||
hash[el] = true; |
hash[el] = true; |
||
hash.byKey.writeln; |
hash.byKey.writeln; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[8, 0, 1, 9, 2, 3]</pre> |
<pre>[8, 0, 1, 9, 2, 3]</pre> |
||
Like code D#1, but with an array returned: |
Like code D#1, but with an array returned: |
||
< |
<syntaxhighlight lang="d">void main() |
||
{ |
{ |
||
import std.stdio, std.algorithm, std.array; |
import std.stdio, std.algorithm, std.array; |
||
Line 895: | Line 2,503: | ||
auto a = [5,4,32,7,6,4,2,6,0,8,6,9].sort.uniq.array; |
auto a = [5,4,32,7,6,4,2,6,0,8,6,9].sort.uniq.array; |
||
a.writeln; |
a.writeln; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[0, 2, 4, 5, 6, 7, 8, 9, 32]</pre> |
<pre>[0, 2, 4, 5, 6, 7, 8, 9, 32]</pre> |
||
Line 902: | Line 2,510: | ||
Generics were added in Delphi2009. |
Generics were added in Delphi2009. |
||
< |
<syntaxhighlight lang="delphi">program RemoveDuplicateElements; |
||
{$APPTYPE CONSOLE} |
{$APPTYPE CONSOLE} |
||
Line 925: | Line 2,533: | ||
lIntegerList.Free; |
lIntegerList.Free; |
||
end; |
end; |
||
end.</ |
end.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 936: | Line 2,544: | ||
=={{header|Déjà Vu}}== |
=={{header|Déjà Vu}}== |
||
< |
<syntaxhighlight lang="dejavu">} |
||
for item in [ 1 10 1 :hi :hello :hi :hi ]: |
for item in [ 1 10 1 :hi :hello :hi :hi ]: |
||
@item |
@item |
||
!. keys set{</ |
!. keys set{</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[ 1 :hello 10 :hi ]</pre> |
<pre>[ 1 :hello 10 :hi ]</pre> |
||
Line 945: | Line 2,553: | ||
=={{header|E}}== |
=={{header|E}}== |
||
< |
<syntaxhighlight lang="e">[1,2,3,2,3,4].asSet().getElements()</syntaxhighlight> |
||
=={{header|EasyLang}}== |
|||
<syntaxhighlight lang="easylang"> |
|||
a[] = [ 1 2 1 4 5 2 15 1 3 4 ] |
|||
for a in a[] |
|||
found = 0 |
|||
for b in b[] |
|||
if a = b |
|||
found = 1 |
|||
break 1 |
|||
. |
|||
. |
|||
if found = 0 |
|||
b[] &= a |
|||
. |
|||
. |
|||
print b[] |
|||
</syntaxhighlight> |
|||
=={{header|ECL}}== |
=={{header|ECL}}== |
||
< |
<syntaxhighlight lang="ecl"> |
||
inNumbers := DATASET([{1},{2},{3},{4},{1},{1},{7},{8},{9},{9},{0},{0},{3},{3},{3},{3},{3}], {INTEGER Field1}); |
inNumbers := DATASET([{1},{2},{3},{4},{1},{1},{7},{8},{9},{9},{0},{0},{3},{3},{3},{3},{3}], {INTEGER Field1}); |
||
DEDUP(SORT(inNumbers,Field1)); |
DEDUP(SORT(inNumbers,Field1)); |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>0 |
<pre>0 |
||
Line 964: | Line 2,592: | ||
=={{header|Elena}}== |
=={{header|Elena}}== |
||
ELENA |
ELENA 6.x : |
||
< |
<syntaxhighlight lang="elena">import extensions; |
||
import system'collections; |
import system'collections; |
||
import system'routines; |
import system'routines; |
||
Line 974: | Line 2,602: | ||
auto unique := new Map<int, int>(); |
auto unique := new Map<int, int>(); |
||
nums.forEach:(n){ unique[n] := n }; |
nums.forEach::(n){ unique[n] := n }; |
||
console.printLine(unique.MapValues.asEnumerable()) |
console.printLine(unique.MapValues.asEnumerable()) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
1,2,3,4 |
1,2,3,4 |
||
</pre> |
|||
=={{header|Ecstasy}}== |
|||
<syntaxhighlight lang="java"> |
|||
module RetainUniqueValues { |
|||
void run() { |
|||
Int[] array = [1, 2, 3, 2, 1, 2, 3, 4, 5, 3, 2, 1]; |
|||
array = array.distinct().toArray(); |
|||
@Inject Console console; |
|||
console.print($"result={array}"); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
result=[1, 2, 3, 4, 5] |
|||
</pre> |
</pre> |
||
Line 986: | Line 2,632: | ||
Elixir has an <code>Enum.uniq</code> built-in function. |
Elixir has an <code>Enum.uniq</code> built-in function. |
||
{{works with|Elixir|1.2}} |
{{works with|Elixir|1.2}} |
||
< |
<syntaxhighlight lang="elixir">defmodule RC do |
||
# Set approach |
# Set approach |
||
def uniq1(list), do: MapSet.new(list) |> MapSet.to_list |
def uniq1(list), do: MapSet.new(list) |> MapSet.to_list |
||
Line 1,012: | Line 2,658: | ||
end) |
end) |
||
|> fn{t,_} -> IO.puts "#{inspect fun}:\t#{t/1000000}\t#{inspect result}" end.() |
|> fn{t,_} -> IO.puts "#{inspect fun}:\t#{t/1000000}\t#{inspect result}" end.() |
||
end)</ |
end)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,024: | Line 2,670: | ||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
< |
<syntaxhighlight lang="erlang">List = [1, 2, 3, 2, 2, 4, 5, 5, 4, 6, 6, 5]. |
||
UniqueList = gb_sets:to_list(gb_sets:from_list(List)). |
UniqueList = gb_sets:to_list(gb_sets:from_list(List)). |
||
% Alternatively the builtin: |
% Alternatively the builtin: |
||
Unique_list = lists:usort( List ). |
Unique_list = lists:usort( List ). |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Euphoria}}== |
=={{header|Euphoria}}== |
||
< |
<syntaxhighlight lang="euphoria">include sort.e |
||
function uniq(sequence s) |
function uniq(sequence s) |
||
Line 1,047: | Line 2,693: | ||
constant s = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4} |
constant s = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4} |
||
? s |
? s |
||
? uniq(s)</ |
? uniq(s)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,056: | Line 2,702: | ||
=={{header|F Sharp|F#}}== |
=={{header|F Sharp|F#}}== |
||
The simplest way is to build a set from the given array (this actually works for any enumerable input sequence type, not just arrays): |
The simplest way is to build a set from the given array (this actually works for any enumerable input sequence type, not just arrays): |
||
< |
<syntaxhighlight lang="fsharp"> |
||
set [|1;2;3;2;3;4|] |
set [|1;2;3;2;3;4|] |
||
</syntaxhighlight> |
|||
</lang> |
|||
gives: |
gives: |
||
< |
<syntaxhighlight lang="fsharp"> |
||
val it : Set<int> = seq [1; 2; 3; 4] |
val it : Set<int> = seq [1; 2; 3; 4] |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
< |
<syntaxhighlight lang="factor">USING: sets ; |
||
V{ 1 2 1 3 2 4 5 } members . |
V{ 1 2 1 3 2 4 5 } members . |
||
V{ 1 2 3 4 5 }</ |
V{ 1 2 3 4 5 }</syntaxhighlight> |
||
=={{header|Forth}}== |
=={{header|Forth}}== |
||
Line 1,079: | Line 2,725: | ||
The input data is assumed to be sorted. |
The input data is assumed to be sorted. |
||
< |
<syntaxhighlight lang="forth">\ Increments a2 until it no longer points to the same value as a1 |
||
\ a3 is the address beyond the data a2 is traversing. |
\ a3 is the address beyond the data a2 is traversing. |
||
: skip-dups ( a1 a2 a3 -- a1 a2+n ) |
: skip-dups ( a1 a2 a3 -- a1 a2+n ) |
||
Line 1,097: | Line 2,743: | ||
cell+ r@ skip-dups |
cell+ r@ skip-dups |
||
cell 0 d+ \ increment write ptr only |
cell 0 d+ \ increment write ptr only |
||
repeat r> 2drop r> - cell / ;</ |
repeat r> 2drop r> - cell / ;</syntaxhighlight> |
||
Here is another implementation of "uniq" that uses a popular parameters and local variables extension words. It is structurally the same as the above implementation, but uses less overt stack manipulation. |
Here is another implementation of "uniq" that uses a popular parameters and local variables extension words. It is structurally the same as the above implementation, but uses less overt stack manipulation. |
||
< |
<syntaxhighlight lang="forth">: uniqv { a n \ r e -- n } |
||
a n cells+ to e |
a n cells+ to e |
||
a dup to r |
a dup to r |
||
Line 1,112: | Line 2,758: | ||
cell+ |
cell+ |
||
repeat |
repeat |
||
a - cell / ;</ |
a - cell / ;</syntaxhighlight> |
||
To test this code, you can execute: |
To test this code, you can execute: |
||
< |
<syntaxhighlight lang="forth">create test 1 , 2 , 3 , 2 , 6 , 4 , 5 , 3 , 6 , |
||
here test - cell / constant ntest |
here test - cell / constant ntest |
||
: .test ( n -- ) 0 ?do test i cells + ? loop ; |
: .test ( n -- ) 0 ?do test i cells + ? loop ; |
||
test ntest 2dup cell-sort uniq .test</ |
test ntest 2dup cell-sort uniq .test</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,128: | Line 2,774: | ||
Fortran has no built-in hash functions or sorting functions but the code below implements the compare all elements algorithm. |
Fortran has no built-in hash functions or sorting functions but the code below implements the compare all elements algorithm. |
||
< |
<syntaxhighlight lang="fortran"> |
||
program remove_dups |
program remove_dups |
||
Line 1,155: | Line 2,801: | ||
end program remove_dups |
end program remove_dups |
||
</syntaxhighlight> |
|||
</lang> |
|||
Same as above but using 'ANY' to check if the input number already exists in the array of unique elements: |
Same as above but using 'ANY' to check if the input number already exists in the array of unique elements: |
||
< |
<syntaxhighlight lang="fortran"> |
||
program remove_dups |
program remove_dups |
||
implicit none |
implicit none |
||
Line 1,182: | Line 2,828: | ||
end program remove_dups |
end program remove_dups |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>Unique list has 6 elements: 1 2 3 4 5 6</pre> |
<pre>Unique list has 6 elements: 1 2 3 4 5 6</pre> |
||
=={{header|FreeBASIC}}== |
|||
<lang freebasic>' FB 1.05.0 Win64 |
|||
Sub removeDuplicates(a() As Integer, b() As Integer) |
|||
Dim lb As Integer = LBound(a) |
|||
Dim ub As Integer = UBound(a) |
|||
If ub = -1 Then Return '' empty array |
|||
Redim b(lb To ub) |
|||
b(lb) = a(lb) |
|||
Dim count As Integer = 1 |
|||
Dim unique As Boolean |
|||
For i As Integer = lb + 1 To ub |
|||
unique = True |
|||
For j As Integer = lb to i - 1 |
|||
If a(i) = a(j) Then |
|||
unique = False |
|||
Exit For |
|||
End If |
|||
Next j |
|||
If unique Then |
|||
b(lb + count) = a(i) |
|||
count += 1 |
|||
End If |
|||
Next i |
|||
If count > 0 Then Redim Preserve b(lb To lb + count - 1) |
|||
End Sub |
|||
Dim a(1 To 10) As Integer = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4} |
|||
Dim b() As Integer |
|||
removeDuplicates a(), b() |
|||
For i As Integer = LBound(b) To UBound(b) |
|||
Print b(i); " "; |
|||
Next |
|||
Print |
|||
Print "Press any key to quit" |
|||
Sleep</lang> |
|||
{{out}} |
|||
<pre> |
|||
1 2 4 5 15 3 |
|||
</pre> |
|||
=={{header|Frink}}== |
=={{header|Frink}}== |
||
The following demonstrates two of the simplest ways of removing duplicates. |
The following demonstrates two of the simplest ways of removing duplicates. |
||
< |
<syntaxhighlight lang="frink"> |
||
b = [1, 5, 2, 6, 6, 2, 2, 1, 9, 8, 6, 5] |
b = [1, 5, 2, 6, 6, 2, 2, 1, 9, 8, 6, 5] |
||
Line 1,245: | Line 2,846: | ||
// Another way, using the "set" datatype and back to an array. |
// Another way, using the "set" datatype and back to an array. |
||
println[toArray[toSet[b]] |
println[toArray[toSet[b]] |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} Note that sets are not guaranteed to be printed in any specific order. |
{{out}} Note that sets are not guaranteed to be printed in any specific order. |
||
Line 1,251: | Line 2,852: | ||
[1, 2, 5, 6, 8, 9] |
[1, 2, 5, 6, 8, 9] |
||
[9, 8, 6, 5, 2, 1] |
[9, 8, 6, 5, 2, 1] |
||
</pre> |
|||
=={{header|Gambas}}== |
|||
'''[https://gambas-playground.proko.eu/?gist=1e2bb524d2278cd88bccdc21a1683296 Click this link to run this code]''' |
|||
<lang gambas>Public Sub Main() |
|||
Dim sString As String[] = Split("Now is the time for all the good men to come to the aid of the good party 1 2 1 3 3 3 2 1 1 2 3 4 33 2 5 4 333 5", " ") |
|||
Dim sFix As New String[] |
|||
Dim sTemp As String |
|||
For Each sTemp In sString |
|||
sTemp &= " " |
|||
If InStr(sFix.Join(" ") & " ", sTemp) Then Continue |
|||
sFix.Add(Trim(sTemp)) |
|||
Next |
|||
Print sFix.Join(" ") |
|||
End</lang> |
|||
Output: |
|||
<pre> |
|||
Now is the time for all good men to come aid of party 1 2 3 4 33 5 333 |
|||
</pre> |
</pre> |
||
=={{header|GAP}}== |
=={{header|GAP}}== |
||
< |
<syntaxhighlight lang="gap"># Built-in, using sets (which are also lists) |
||
a := [ 1, 2, 3, 1, [ 4 ], 5, 5, [4], 6 ]; |
a := [ 1, 2, 3, 1, [ 4 ], 5, 5, [4], 6 ]; |
||
# [ 1, 2, 3, 1, [ 4 ], 5, 5, [ 4 ], 6 ] |
# [ 1, 2, 3, 1, [ 4 ], 5, 5, [ 4 ], 6 ] |
||
Line 1,283: | Line 2,863: | ||
# true |
# true |
||
IsList(b); |
IsList(b); |
||
# true</ |
# true</syntaxhighlight> |
||
=={{header|Go}}== |
=={{header|Go}}== |
||
===Map solution=== |
===Map solution=== |
||
< |
<syntaxhighlight lang="go">package main |
||
import "fmt" |
import "fmt" |
||
Line 1,305: | Line 2,885: | ||
func main() { |
func main() { |
||
fmt.Println(uniq([]int{1, 2, 3, 2, 3, 4})) // prints: [3 4 1 2] (but in a semi-random order) |
fmt.Println(uniq([]int{1, 2, 3, 2, 3, 4})) // prints: [3 4 1 2] (but in a semi-random order) |
||
}</ |
}</syntaxhighlight> |
||
===Map preserving order=== |
===Map preserving order=== |
||
It takes only small changes to the above code to preserver order. Just store the sequence in the map: |
It takes only small changes to the above code to preserver order. Just store the sequence in the map: |
||
< |
<syntaxhighlight lang="go">package main |
||
import "fmt" |
import "fmt" |
||
Line 1,330: | Line 2,910: | ||
func main() { |
func main() { |
||
fmt.Println(uniq([]int{1, 2, 3, 2, 3, 4})) // prints: [1 2 3 4] |
fmt.Println(uniq([]int{1, 2, 3, 2, 3, 4})) // prints: [1 2 3 4] |
||
}</ |
}</syntaxhighlight> |
||
===Float64, removing duplicate NaNs=== |
===Float64, removing duplicate NaNs=== |
||
In solutions above, you just replace <code>int</code> with another type to use for a list of another type. (See [[Associative_arrays/Creation#Go]] for acceptable types.) Except a weird thing happens with NaNs. They (correctly) don't compare equal, so you have to special case them if you want to remove duplicate NaNs: |
In solutions above, you just replace <code>int</code> with another type to use for a list of another type. (See [[Associative_arrays/Creation#Go]] for acceptable types.) Except a weird thing happens with NaNs. They (correctly) don't compare equal, so you have to special case them if you want to remove duplicate NaNs: |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 1,367: | Line 2,947: | ||
func main() { |
func main() { |
||
fmt.Println(uniq([]float64{1, 2, math.NaN(), 2, math.NaN(), 4})) // Prints [1 2 NaN 4] |
fmt.Println(uniq([]float64{1, 2, math.NaN(), 2, math.NaN(), 4})) // Prints [1 2 NaN 4] |
||
}</ |
}</syntaxhighlight> |
||
===Any type using reflection=== |
===Any type using reflection=== |
||
Go doesn't have templates or generics, but it does have reflection. |
Go doesn't have templates or generics, but it does have reflection. |
||
Line 1,376: | Line 2,956: | ||
Note: due to details with how Go handles map keys that contain a NaN somewhere (including within a complex or even within a sub struct field) this version simply omits any NaN containing values it comes across and returns a bool to indicate if that happened. This version is otherwise a translation of the above order preserving map implementation, it does not for example call reflect.DeepEqual so elements with pointers to distinct but equal values will be treated as non-equal. |
Note: due to details with how Go handles map keys that contain a NaN somewhere (including within a complex or even within a sub struct field) this version simply omits any NaN containing values it comes across and returns a bool to indicate if that happened. This version is otherwise a translation of the above order preserving map implementation, it does not for example call reflect.DeepEqual so elements with pointers to distinct but equal values will be treated as non-equal. |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 1,465: | Line 3,045: | ||
//uniq(a) |
//uniq(a) |
||
//uniq(nil) |
//uniq(nil) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,478: | Line 3,058: | ||
=={{header|Groovy}}== |
=={{header|Groovy}}== |
||
< |
<syntaxhighlight lang="groovy">def list = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'] |
||
assert list.size() == 12 |
assert list.size() == 12 |
||
println " Original List: ${list}" |
println " Original List: ${list}" |
||
Line 1,499: | Line 3,079: | ||
def set = list as Set |
def set = list as Set |
||
assert set.size() == 8 |
assert set.size() == 8 |
||
println " Set: ${set}"</ |
println " Set: ${set}"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,506: | Line 3,086: | ||
Original List, filtered: [1, 2, 3, a, b, c, 4, d] |
Original List, filtered: [1, 2, 3, a, b, c, 4, d] |
||
Set: [1, 2, 3, a, b, c, 4, d]</pre> |
Set: [1, 2, 3, a, b, c, 4, d]</pre> |
||
=={{header|GW-BASIC}}== |
|||
{{trans|Modula-2}} |
|||
{{works with|PC-BASIC|any}} |
|||
<lang qbasic> |
|||
10 ' Remove Duplicates |
|||
20 OPTION BASE 1 |
|||
30 LET MAXI% = 7 |
|||
40 DIM D(7), R(7): ' data, result |
|||
50 ' Set the data. |
|||
60 FOR I% = 1 TO 7 |
|||
70 READ D(I%) |
|||
80 NEXT I% |
|||
90 ' Remove duplicates. |
|||
100 LET R(1) = D(1) |
|||
110 LET LRI% = 1: ' last index of result |
|||
120 LET P% = 1: ' position |
|||
130 WHILE P% < MAXI% |
|||
140 LET P% = P% + 1 |
|||
150 LET ISNEW = 1: ' is a new number? |
|||
160 LET RI% = 1: ' current index of result |
|||
170 WHILE (RI% <= LRI%) AND ISNEW |
|||
180 IF D(P%) = R(RI%) THEN LET ISNEW = 0 |
|||
190 LET RI% = RI% + 1 |
|||
200 WEND |
|||
210 IF ISNEW THEN LET LRI% = LRI% + 1: LET R(LRI%) = D(P%) |
|||
220 WEND |
|||
230 FOR RI% = 1 TO LRI% |
|||
240 PRINT R(RI%) |
|||
250 NEXT RI% |
|||
260 END |
|||
1000 DATA 1, 2, 2, 3, 4, 5, 5 |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
</pre> |
|||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
===Usage=== |
===Usage=== |
||
<syntaxhighlight lang="haskell"> print $ unique [4, 5, 4, 2, 3, 3, 4] |
|||
[4,5,2,3]</syntaxhighlight> |
|||
<lang haskell> print $ unique [4, 5, 4, 2, 3, 3, 4] |
|||
[4,5,2,3]</lang> |
|||
===Sorted result using Set=== |
===Sorted result using Set=== |
||
Line 1,560: | Line 3,097: | ||
O(n ln(n)). Requires there is a partial ordering of elements. |
O(n ln(n)). Requires there is a partial ordering of elements. |
||
< |
<syntaxhighlight lang="haskell">import qualified Data.Set as Set |
||
unique :: Ord a => [a] -> [a] |
unique :: Ord a => [a] -> [a] |
||
unique = Set.toList . Set.fromList</ |
unique = Set.toList . Set.fromList</syntaxhighlight> |
||
===Unsorted result using Set=== |
===Unsorted result using Set=== |
||
Line 1,569: | Line 3,106: | ||
O(n ln(n)). Retains original order. Requires there is a partial ordering of elements. |
O(n ln(n)). Retains original order. Requires there is a partial ordering of elements. |
||
< |
<syntaxhighlight lang="haskell">import Data.Set |
||
unique :: Ord a => [a] -> [a] |
unique :: Ord a => [a] -> [a] |
||
Line 1,576: | Line 3,113: | ||
loop s [] = [] |
loop s [] = [] |
||
loop s (x : xs) | member x s = loop s xs |
loop s (x : xs) | member x s = loop s xs |
||
| otherwise = x : loop (insert x s) xs</ |
| otherwise = x : loop (insert x s) xs</syntaxhighlight> |
||
===Using filter=== |
===Using filter=== |
||
Line 1,582: | Line 3,119: | ||
O(n^2). Retains original order. Only requires that elements can be compared for equality. |
O(n^2). Retains original order. Only requires that elements can be compared for equality. |
||
< |
<syntaxhighlight lang="haskell">import Data.List |
||
unique :: Eq a => [a] -> [a] |
unique :: Eq a => [a] -> [a] |
||
unique [] = [] |
unique [] = [] |
||
unique (x : xs) = x : unique (filter (x /=) xs)</ |
unique (x : xs) = x : unique (filter (x /=) xs)</syntaxhighlight> |
||
===Standard Library=== |
===Standard Library=== |
||
< |
<syntaxhighlight lang="haskell">import Data.List |
||
Data.List.nub :: Eq a => [a] -> [a] |
Data.List.nub :: Eq a => [a] -> [a] |
||
Data.List.Unique.unique :: Ord a => [a] -> [a]</ |
Data.List.Unique.unique :: Ord a => [a] -> [a]</syntaxhighlight> |
||
=={{header|HicEst}}== |
=={{header|HicEst}}== |
||
< |
<syntaxhighlight lang="hicest">REAL :: nums(12) |
||
CHARACTER :: workspace*100 |
CHARACTER :: workspace*100 |
||
Line 1,603: | Line 3,140: | ||
READ(Text=workspace, ItemS=individuals) nums ! convert to numeric |
READ(Text=workspace, ItemS=individuals) nums ! convert to numeric |
||
WRITE(ClipBoard) individuals, "individuals: ", nums ! 6 individuals: 0 1 2 3 8 9 0 0 0 0 0 0 </ |
WRITE(ClipBoard) individuals, "individuals: ", nums ! 6 individuals: 0 1 2 3 8 9 0 0 0 0 0 0 </syntaxhighlight> |
||
=={{header|Icon}} and {{header|Unicon}}== |
=={{header|Icon}} and {{header|Unicon}}== |
||
This solution preserves the original order of the elements. |
This solution preserves the original order of the elements. |
||
< |
<syntaxhighlight lang="icon">procedure main(args) |
||
every write(!noDups(args)) |
every write(!noDups(args)) |
||
end |
end |
||
Line 1,621: | Line 3,158: | ||
return a |
return a |
||
} |
} |
||
end</ |
end</syntaxhighlight> |
||
A sample run is: |
A sample run is: |
||
<pre> |
<pre> |
||
Line 1,635: | Line 3,172: | ||
=={{header|IDL}}== |
=={{header|IDL}}== |
||
< |
<syntaxhighlight lang="idl">non_repeated_values = array[uniq(array, sort( array))]</syntaxhighlight> |
||
=={{header|Inform 7}}== |
=={{header|Inform 7}}== |
||
< |
<syntaxhighlight lang="inform7">To decide which list of Ks is (L - list of values of kind K) without duplicates: |
||
let result be a list of Ks; |
let result be a list of Ks; |
||
repeat with X running through L: |
repeat with X running through L: |
||
add X to result, if absent; |
add X to result, if absent; |
||
decide on result.</ |
decide on result.</syntaxhighlight> |
||
=={{header|IS-BASIC}}== |
|||
<lang IS-BASIC>100 PROGRAM "RemoveDu.bas" |
|||
110 RANDOMIZE |
|||
120 NUMERIC ARR(1 TO 20),TOP |
|||
130 LET TOP=FILL(ARR) |
|||
140 CALL WRITE(ARR,TOP) |
|||
150 LET TOP=REMOVE(ARR) |
|||
160 CALL WRITE(ARR,TOP) |
|||
170 DEF WRITE(REF A,N) |
|||
180 FOR I=1 TO N |
|||
190 PRINT A(I); |
|||
200 NEXT |
|||
210 PRINT |
|||
220 END DEF |
|||
230 DEF FILL(REF A) |
|||
240 LET FILL=UBOUND(A):LET A(LBOUND(A))=1 |
|||
250 FOR I=LBOUND(A)+1 TO UBOUND(A) |
|||
260 LET A(I)=A(I-1)+RND(3) |
|||
270 NEXT |
|||
280 END DEF |
|||
290 DEF REMOVE(REF A) |
|||
300 LET ST=0 |
|||
310 FOR I=LBOUND(A)+1 TO UBOUND(A) |
|||
320 IF A(I-1)=A(I) THEN LET ST=ST+1 |
|||
330 IF ST>0 THEN LET A(I-ST)=A(I) |
|||
340 NEXT |
|||
350 LET REMOVE=UBOUND(A)-ST |
|||
360 END DEF</lang> |
|||
{{out}} |
|||
<pre>START |
|||
1 1 2 4 5 7 9 10 12 14 16 16 16 17 18 20 20 22 23 23 |
|||
1 2 4 5 7 9 10 12 14 16 17 18 20 22 23 |
|||
ok |
|||
START |
|||
1 2 4 5 5 5 7 8 9 9 10 10 10 12 14 15 17 17 18 20 |
|||
1 2 4 5 7 8 9 10 12 14 15 17 18 20 |
|||
ok |
|||
START |
|||
1 3 3 4 5 6 8 10 11 12 14 16 16 16 16 18 18 19 21 21 |
|||
1 3 4 5 6 8 10 11 12 14 16 18 19 21 |
|||
ok |
|||
START |
|||
1 3 3 4 5 5 7 9 11 13 13 14 16 17 17 18 19 19 20 21 |
|||
1 3 4 5 7 9 11 13 14 16 17 18 19 20 21 |
|||
ok |
|||
START |
|||
1 2 3 5 5 6 6 7 8 10 12 14 15 17 17 19 21 23 25 25 |
|||
1 2 3 5 6 7 8 10 12 14 15 17 19 21 23 25 |
|||
ok</pre> |
|||
=={{header|J}}== |
=={{header|J}}== |
||
The verb<code> ~. </code>removes duplicate items from ''any'' array (numeric, character, or other; vector, matrix, rank-n array). For example: |
The verb<code> ~. </code>removes duplicate items from ''any'' array (numeric, character, or other; vector, matrix, rank-n array). For example: |
||
< |
<syntaxhighlight lang="j"> ~. 4 3 2 8 0 1 9 5 1 7 6 3 9 9 4 2 1 5 3 2 |
||
4 3 2 8 0 1 9 5 7 6 |
4 3 2 8 0 1 9 5 7 6 |
||
~. 'chthonic eleemosynary paronomasiac' |
~. 'chthonic eleemosynary paronomasiac' |
||
chtoni elmsyarp</ |
chtoni elmsyarp</syntaxhighlight> |
||
Or (since J defines an item of an n dimensional array as its n-1 dimensional sub arrays): |
Or (since J defines an item of an n dimensional array as its n-1 dimensional sub arrays): |
||
< |
<syntaxhighlight lang="j"> 0 1 1 2 0 */0 1 2 |
||
0 0 0 |
0 0 0 |
||
0 1 2 |
0 1 2 |
||
Line 1,713: | Line 3,200: | ||
0 0 0 |
0 0 0 |
||
0 1 2 |
0 1 2 |
||
0 2 4</ |
0 2 4</syntaxhighlight> |
||
=={{header|Jakt}}== |
|||
The array version preserves order based on first occurrence. |
|||
<syntaxhighlight lang="jakt"> |
|||
fn deduplicated<T>(anon array: [T]) throws -> [T] { |
|||
mut existing_items: {T} = {} |
|||
mut result: [T] = [] |
|||
for value in array { |
|||
if not existing_items.contains(value) { |
|||
existing_items.add(value) |
|||
result.push(value) |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
fn deduplicated_set<T>(anon array: [T]) throws -> {T} { |
|||
mut result: {T} = {} |
|||
for value in array { |
|||
result.add(value) |
|||
} |
|||
return result |
|||
} |
|||
fn main() { |
|||
let array = [1, 2, 3, 3, 2, 5, 4] |
|||
println("{}", deduplicated(array)) |
|||
println("{}", deduplicated_set(array)) |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
There is more than 1 way to achieve this. The most logical approach will depend on your application.<br /> |
|||
<syntaxhighlight lang="java"> |
|||
import java.util.ArrayList; |
|||
import java.util.Iterator; |
|||
import java.util.LinkedHashSet; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
</syntaxhighlight> |
|||
One way would be to add the values to a ''Set'' object, which only allows for unique values. |
|||
<syntaxhighlight lang="java"> |
|||
int[] removeDuplicates(int[] values) { |
|||
/* use a LinkedHashSet to preserve order */ |
|||
Set<Integer> set = new LinkedHashSet<>(); |
|||
for (int value : values) |
|||
set.add(value); |
|||
values = new int[set.size()]; |
|||
Iterator<Integer> iterator = set.iterator(); |
|||
int index = 0; |
|||
while (iterator.hasNext()) |
|||
values[index++] = iterator.next(); |
|||
return values; |
|||
} |
|||
</syntaxhighlight> |
|||
Alternately, you could simply add the values to a mutable ''List'', checking if the list already contains the value before adding it. |
|||
<syntaxhighlight lang="java"> |
|||
int[] removeDuplicates(int[] values) { |
|||
List<Integer> list = new ArrayList<>(); |
|||
for (int value : values) |
|||
if (!list.contains(value)) list.add(value); |
|||
values = new int[list.size()]; |
|||
int index = 0; |
|||
for (int value : list) |
|||
values[index++] = value; |
|||
return values; |
|||
} |
|||
</syntaxhighlight> |
|||
<pre> |
|||
[2, 1, 4, 1, 1, 3, 1, 3, 1, 4, 3, 2, 3, 4, 3, 2, 2, 3, 3, 3] |
|||
[2, 1, 4, 3] |
|||
[2, 4, 1, 4, 1, 4, 3, 1, 1, 3, 4, 4, 4, 4, 2, 1, 1, 2, 3, 2] |
|||
[2, 4, 1, 3] |
|||
</pre> |
|||
<br /> |
|||
Alternate approaches |
|||
{{works with|Java|1.5}} |
{{works with|Java|1.5}} |
||
< |
<syntaxhighlight lang="java5">import java.util.*; |
||
class Test { |
class Test { |
||
Line 1,728: | Line 3,292: | ||
System.out.printf("%s ", o); |
System.out.printf("%s ", o); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
<pre>1 a 2 b 3 c d</pre> |
<pre>1 a 2 b 3 c d</pre> |
||
{{works with|Java|8}} |
{{works with|Java|8}} |
||
< |
<syntaxhighlight lang="java">import java.util.*; |
||
class Test { |
class Test { |
||
Line 1,741: | Line 3,305: | ||
Arrays.stream(data).distinct().forEach((o) -> System.out.printf("%s ", o)); |
Arrays.stream(data).distinct().forEach((o) -> System.out.printf("%s ", o)); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
<pre>1 2 3 a b c d</pre> |
<pre>1 2 3 a b c d</pre> |
||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
This uses the <code>===</code> "strict equality" operator, which does no type conversions (<code>4 == "4"</code> is true but <code>4 === "4"</code> is false) |
This uses the <code>===</code> "strict equality" operator, which does no type conversions (<code>4 == "4"</code> is true but <code>4 === "4"</code> is false) |
||
< |
<syntaxhighlight lang="javascript">function unique(ary) { |
||
// concat() with no args is a way to clone an array |
// concat() with no args is a way to clone an array |
||
var u = ary.concat().sort(); |
var u = ary.concat().sort(); |
||
Line 1,761: | Line 3,325: | ||
var uniq = unique(ary); |
var uniq = unique(ary); |
||
for (var i = 0; i < uniq.length; i++) |
for (var i = 0; i < uniq.length; i++) |
||
print(uniq[i] + "\t" + typeof(uniq[i]));</ |
print(uniq[i] + "\t" + typeof(uniq[i]));</syntaxhighlight> |
||
<pre>1 - number |
<pre>1 - number |
||
2 - number |
2 - number |
||
Line 1,773: | Line 3,337: | ||
Or, extend the prototype for Array: |
Or, extend the prototype for Array: |
||
< |
<syntaxhighlight lang="javascript">Array.prototype.unique = function() { |
||
var u = this.concat().sort(); |
var u = this.concat().sort(); |
||
for (var i = 1; i < u.length; ) { |
for (var i = 1; i < u.length; ) { |
||
Line 1,783: | Line 3,347: | ||
return u; |
return u; |
||
} |
} |
||
var uniq = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"].unique();</ |
var uniq = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"].unique();</syntaxhighlight> |
||
With reduce and arrow functions (ES6): |
With reduce and arrow functions (ES6): |
||
< |
<syntaxhighlight lang="javascript">Array.prototype.unique = function() { |
||
return this.sort().reduce( (a,e) => e === a[a.length-1] ? a : (a.push(e), a), [] ) |
return this.sort().reduce( (a,e) => e === a[a.length-1] ? a : (a.push(e), a), [] ) |
||
}</ |
}</syntaxhighlight> |
||
With sets and spread operator (ES6): |
With sets and spread operator (ES6): |
||
< |
<syntaxhighlight lang="javascript">Array.prototype.unique = function() { |
||
return [... new Set(this)] |
return [... new Set(this)] |
||
}</ |
}</syntaxhighlight> |
||
If, however, the array is homogenous, or we wish to interpret it as such by using JavaScript's Abstract Equality comparison (as in '==', see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) then it proves significantly faster to use a hash table. |
If, however, the array is homogenous, or we wish to interpret it as such by using JavaScript's Abstract Equality comparison (as in '==', see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) then it proves significantly faster to use a hash table. |
||
Line 1,799: | Line 3,363: | ||
For example, in ES 5: |
For example, in ES 5: |
||
< |
<syntaxhighlight lang="javascript">function uniq(lst) { |
||
var u = [], |
var u = [], |
||
dct = {}, |
dct = {}, |
||
Line 1,813: | Line 3,377: | ||
return u; |
return u; |
||
}</ |
}</syntaxhighlight> |
||
Or, to allow for customised definitions of equality and duplication, we can follow the Haskell prelude in defining a '''nub :: [a] -> [a] function''' which is a special case of '''nubBy :: (a -> a -> Bool) -> [a] -> [a]''' |
Or, to allow for customised definitions of equality and duplication, we can follow the Haskell prelude in defining a '''nub :: [a] -> [a] function''' which is a special case of '''nubBy :: (a -> a -> Bool) -> [a] -> [a]''' |
||
Line 1,819: | Line 3,383: | ||
{{trans|Haskell}} |
{{trans|Haskell}} |
||
< |
<syntaxhighlight lang="javascript">(function () { |
||
'use strict'; |
'use strict'; |
||
Line 1,857: | Line 3,421: | ||
] |
] |
||
})();</ |
})();</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>[[4, 3, 2, 8, 0, 1, 9, 5, 7, 6], "chtoni elmsyarp"]</pre> |
<pre>[[4, 3, 2, 8, 0, 1, 9, 5, 7, 6], "chtoni elmsyarp"]</pre> |
||
=={{header|Joy}}== |
|||
<syntaxhighlight lang="joy">DEFINE uniq == [[]] [[in] [swap pop] [cons] ifte] primrec.</syntaxhighlight> |
|||
=={{header|jq}}== |
=={{header|jq}}== |
||
If it is acceptable to alter the ordering of elements, then |
If it is acceptable to alter the ordering of elements, then |
||
the builtin (fast) filter, '''unique''', can be used. It can be used for arrays with elements of any JSON type and returns the distinct elements in sorted order. |
the builtin (fast) filter, '''unique''', can be used. It can be used for arrays with elements of any JSON type and returns the distinct elements in sorted order. |
||
< |
<syntaxhighlight lang="jq">[4,3,2,1,1,2,3,4] | unique</syntaxhighlight> |
||
If all but the first occurrence of each element should be deleted, then the following function could be used. It retains the advantage of imposing no restrictions on the types of elements in the array and for that reason is slightly more complex than would otherwise be required. |
If all but the first occurrence of each element should be deleted, then the following function could be used. It retains the advantage of imposing no restrictions on the types of elements in the array and for that reason is slightly more complex than would otherwise be required. |
||
< |
<syntaxhighlight lang="jq">def removeAllButFirst: |
||
# The hash table functions all expect the hash table to be the input. |
# The hash table functions all expect the hash table to be the input. |
||
Line 1,894: | Line 3,461: | ||
| .[0]; |
| .[0]; |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
{{works with|Julia|0.6}} |
{{works with|Julia|0.6}} |
||
< |
<syntaxhighlight lang="julia">a = [1, 2, 3, 4, 1, 2, 3, 4] |
||
@show unique(a) Set(a)</ |
@show unique(a) Set(a)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,909: | Line 3,476: | ||
(Inspired by the J version.) |
(Inspired by the J version.) |
||
< |
<syntaxhighlight lang="k"> a:4 5#20?13 / create a random 4 x 5 matrix |
||
(12 7 12 4 3 |
(12 7 12 4 3 |
||
6 3 7 4 7 |
6 3 7 4 7 |
||
Line 1,939: | Line 3,506: | ||
(0 0 0 |
(0 0 0 |
||
0 1 2 |
0 1 2 |
||
0 2 4)</ |
0 2 4)</syntaxhighlight> |
||
=={{header|Klingphix}}== |
=={{header|Klingphix}}== |
||
<syntaxhighlight lang="klingphix">( ) |
|||
<lang Klingphix>( ) |
|||
( "Now" "is" "the" "time" "for" "all" "good" "men" "to" "come" "to" "the" "aid" "of" "the" "party." ) |
( "Now" "is" "the" "time" "for" "all" "good" "men" "to" "come" "to" "the" "aid" "of" "the" "party." ) |
||
Line 1,957: | Line 3,524: | ||
swap print drop nl |
swap print drop nl |
||
"End " input</ |
"End " input</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>("Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "aid", "of", "party.") |
<pre>("Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "aid", "of", "party.") |
||
Line 1,964: | Line 3,531: | ||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
{{trans|Java}} |
{{trans|Java}} |
||
< |
<syntaxhighlight lang="scala">fun main(args: Array<String>) { |
||
val data = listOf(1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d") |
val data = listOf(1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d") |
||
val set = data.distinct() |
val set = data.distinct() |
||
Line 1,970: | Line 3,537: | ||
println(data) |
println(data) |
||
println(set) |
println(set) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[1, 2, 3, a, b, c, 2, 3, 4, b, c, d] |
<pre>[1, 2, 3, a, b, c, 2, 3, 4, b, c, d] |
||
Line 1,976: | Line 3,543: | ||
=={{header|Lang5}}== |
=={{header|Lang5}}== |
||
< |
<syntaxhighlight lang="lang5">: dip swap '_ set execute _ ; |
||
: remove-duplicates |
: remove-duplicates |
||
Line 1,983: | Line 3,550: | ||
0 extract swap "2dup in if drop else append then" dip ; |
0 extract swap "2dup in if drop else append then" dip ; |
||
[1 2 6 3 6 4 5 6] remove-duplicates .</ |
[1 2 6 3 6 4 5 6] remove-duplicates .</syntaxhighlight> |
||
Built-in function: |
Built-in function: |
||
< |
<syntaxhighlight lang="lang5">[1 2 6 3 6 4 5 6] 's distinct |
||
[1 2 6 3 6 4 5 6] 's dress dup union .</ |
[1 2 6 3 6 4 5 6] 's dress dup union .</syntaxhighlight> |
||
=={{header|Lasso}}== |
=={{header|Lasso}}== |
||
< |
<syntaxhighlight lang="lasso ">local( |
||
x = array(3,4,8,1,8,1,4,5,6,8,9,6), |
x = array(3,4,8,1,8,1,4,5,6,8,9,6), |
||
y = array |
y = array |
||
) |
) |
||
with n in #x where #y !>> #n do => { #y->insert(#n) } |
with n in #x where #y !>> #n do => { #y->insert(#n) } |
||
// result: array(3, 4, 8, 1, 5, 6, 9)</ |
// result: array(3, 4, 8, 1, 5, 6, 9)</syntaxhighlight> |
||
=={{header| |
=={{header|Lambdatalk}}== |
||
<syntaxhighlight lang="scheme"> |
|||
LB has arrays, but here the elements are stored in a space-separated string. |
|||
<lang lb> |
|||
a$ =" 1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19 " |
|||
print "Original set of elements = ["; a$; "]" |
|||
{def removedup |
|||
b$ =removeDuplicates$( a$) |
|||
{def removedup.loop |
|||
print "With duplicates removed = ["; b$; "]" |
|||
{lambda {:a :b} |
|||
{if {A.empty? :a} |
|||
then :b |
|||
else {removedup.loop {A.rest :a} |
|||
{if {= {A.in? {A.first :a} :b} -1} |
|||
then {A.addlast! {A.first :a} :b} |
|||
else :b}}}}} |
|||
{lambda {:s} |
|||
{S.replace (\[|\]|,) by space in |
|||
{A.disp |
|||
{removedup.loop {A.new :s} {A.new}}}}}} |
|||
-> removedup |
|||
{removedup 1 2 3 a b c 2 3 4 b c d} |
|||
end |
|||
-> 1 2 3 a b c 4 d |
|||
</syntaxhighlight> |
|||
function removeDuplicates$( in$) |
|||
o$ =" " |
|||
i =1 |
|||
do |
|||
term$ =word$( in$, i, " ") |
|||
if instr( o$, " "; term$; " ") =0 and term$ <>" " then o$ =o$ +term$ +" " |
|||
i =i +1 |
|||
loop until term$ ="" |
|||
removeDuplicates$ =o$ |
|||
end function |
|||
</lang> |
|||
Original set of elements = [ 1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19 ] |
|||
With duplicates removed = [ 1 $23.19 2 elbow 3 Bork 4 ] |
|||
=={{header|Logo}}== |
=={{header|Logo}}== |
||
{{works with|UCB Logo}} |
{{works with|UCB Logo}} |
||
< |
<syntaxhighlight lang="logo">show remdup [1 2 3 a b c 2 3 4 b c d] ; [1 a 2 3 4 b c d]</syntaxhighlight> |
||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang="lua">items = {1,2,3,4,1,2,3,4,"bird","cat","dog","dog","bird"} |
||
flags = {} |
flags = {} |
||
io.write('Unique items are:') |
io.write('Unique items are:') |
||
Line 2,036: | Line 3,599: | ||
end |
end |
||
end |
end |
||
io.write('\n')</ |
io.write('\n')</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Unique items are: 1 2 3 4 bird cat dog</pre> |
<pre>Unique items are: 1 2 3 4 bird cat dog</pre> |
||
Lua doesn't accept Not-a-Number (NaN) and nil as table key, we can handle them like this (Lua 5.3): |
Lua doesn't accept Not-a-Number (NaN) and nil as table key, we can handle them like this (Lua 5.3): |
||
< |
<syntaxhighlight lang="lua">local items = {1,2,3,4,1,2,3,4,0/0,nil,"bird","cat","dog","dog","bird",0/0} |
||
function rmdup(t) |
function rmdup(t) |
||
Line 2,055: | Line 3,618: | ||
end |
end |
||
print(table.concat(rmdup(items),' '))</ |
print(table.concat(rmdup(items),' '))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1 2 3 4 nan bird cat dog</pre> |
<pre>1 2 3 4 nan bird cat dog</pre> |
||
=={{header|M2000 Interpreter}}== |
|||
Example of using a Stack object for two types, number (by default 1 is double type), and a list for fast search, append, delete. A stack object is a collection type, which we can use Push to add on top or use Data to append to bottom. A module call pass parameters to current stack, as a frame over, with the left item at the top of the stack. |
|||
<syntaxhighlight lang="m2000 interpreter"> |
|||
Flush // current stack has no items |
|||
// Number pop a number from stack of values |
|||
// Letter pop a string from stack of values |
|||
Module TestList { |
|||
// current stack has a number, 101 |
|||
// we can create a private stack |
|||
a=stack:=1, 1, "c", "d", 2, 2, 3, 3, 3, "a", "a", "b", "b" |
|||
// A list use key/values or key/Key as value. Keys can be number or strings |
|||
// Duplicate not allowed. Exist( list_type, key_to_exam) return true if key exist |
|||
// Lists are inventories types wich can't hold duplicates (error produce if append a duplicate) |
|||
// Lists have O(1) for insert, delete, search (using Hash Table) |
|||
b=list |
|||
stack a { |
|||
// replace current stack with a, old current stack kept |
|||
while not empty |
|||
if islet then // if is letter (string) |
|||
if not exist(b, stackitem$()) then Append b, letter$ else drop |
|||
else.if not exist(b, stackitem()) then |
|||
Append b, number |
|||
else |
|||
drop // drop the item |
|||
end if |
|||
end while |
|||
} |
|||
// now old current stack return as current stack |
|||
// we can sort the b list |
|||
Sort b |
|||
Print b // print the list, using right align on columns for numbers, left for strings. |
|||
Print Number=101 // true |
|||
} |
|||
TestList 101 |
|||
</syntaxhighlight> |
|||
Actual spaces on the result line are according to column width. Here is just one space. |
|||
{{out}} |
|||
<pre> 1 2 3a b c d</pre> |
|||
=={{header|Maple}}== |
=={{header|Maple}}== |
||
This is simplest with a list, which is an immutable array. |
This is simplest with a list, which is an immutable array. |
||
< |
<syntaxhighlight lang="maple">> L := [ 1, 2, 1, 2, 3, 3, 2, 1, "a", "b", "b", "a", "c", "b" ]; |
||
L := [1, 2, 1, 2, 3, 3, 2, 1, "a", "b", "b", "a", "c", "b"] |
L := [1, 2, 1, 2, 3, 3, 2, 1, "a", "b", "b", "a", "c", "b"] |
||
> [op]({op}(L)); |
> [op]({op}(L)); |
||
[1, 2, 3, "a", "b", "c"]</ |
[1, 2, 3, "a", "b", "c"]</syntaxhighlight> |
||
That is idiomatic, but perhaps a bit cryptic; here is a more verbose equivalent: |
That is idiomatic, but perhaps a bit cryptic; here is a more verbose equivalent: |
||
< |
<syntaxhighlight lang="maple">> convert( convert( L, 'set' ), 'list' ); |
||
[1, 2, 3, "a", "b", "c"]</ |
[1, 2, 3, "a", "b", "c"]</syntaxhighlight> |
||
For an Array, which is mutable, the table solution works well in Maple. |
For an Array, which is mutable, the table solution works well in Maple. |
||
< |
<syntaxhighlight lang="maple">> A := Array( L ): |
||
> for u in A do T[u] := 1 end: Array( [indices]( T, 'nolist' ) ); |
> for u in A do T[u] := 1 end: Array( [indices]( T, 'nolist' ) ); |
||
[1, 2, 3, "c", "a", "b"]</ |
[1, 2, 3, "c", "a", "b"]</syntaxhighlight> |
||
Note that the output (due to the Array() constructor) '''is''' in fact an Array. |
Note that the output (due to the Array() constructor) '''is''' in fact an Array. |
||
=={{header|Mathematica}}== |
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
||
Built-in function: |
Built-in function: |
||
< |
<syntaxhighlight lang="mathematica">DeleteDuplicates[{0, 2, 1, 4, 2, 0, 3, 1, 1, 1, 0, 3}]</syntaxhighlight> |
||
gives back: |
gives back: |
||
< |
<syntaxhighlight lang="mathematica">{0, 2, 1, 4, 3}</syntaxhighlight> |
||
Delete duplicates and return sorted elements: |
Delete duplicates and return sorted elements: |
||
<syntaxhighlight lang="mathematica">Union[{0, 2, 1, 4, 2, 0, 3, 1, 1, 1, 0, 3}]</syntaxhighlight> |
|||
<lang Mathematica> |
|||
Union[{0, 2, 1, 4, 2, 0, 3, 1, 1, 1, 0, 3}]</lang> |
|||
{{out|gives back:}} |
{{out|gives back:}} |
||
< |
<syntaxhighlight lang="mathematica">{0, 1, 2, 3, 4}</syntaxhighlight> |
||
=={{header|MATLAB}}== |
=={{header|MATLAB}}== |
||
MATLAB has a built-in function, "unique(list)", which performs this task. |
MATLAB has a built-in function, "unique(list)", which performs this task. |
||
<br \>Sample Usage: |
<br \>Sample Usage: |
||
< |
<syntaxhighlight lang="matlab">>> unique([1 2 6 3 6 4 5 6]) |
||
ans = |
ans = |
||
1 2 3 4 5 6</ |
1 2 3 4 5 6</syntaxhighlight> |
||
NOTE: The unique function only works for vectors and not for true arrays. |
NOTE: The unique function only works for vectors and not for true arrays. |
||
Line 2,100: | Line 3,703: | ||
=={{header|Maxima}}== |
=={{header|Maxima}}== |
||
< |
<syntaxhighlight lang="maxima">unique([8, 9, 5, 2, 0, 7, 0, 0, 4, 2, 7, 3, 9, 6, 6, 2, 4, 7, 9, 8, 3, 8, 0, 3, 7, 0, 2, 7, 6, 0]); |
||
[0, 2, 3, 4, 5, 6, 7, 8, 9]</ |
[0, 2, 3, 4, 5, 6, 7, 8, 9]</syntaxhighlight> |
||
=={{header|MAXScript}}== |
=={{header|MAXScript}}== |
||
< |
<syntaxhighlight lang="maxscript">uniques = #(1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d") |
||
for i in uniques.count to 1 by -1 do |
for i in uniques.count to 1 by -1 do |
||
( |
( |
||
id = findItem uniques uniques[i] |
id = findItem uniques uniques[i] |
||
if (id != i) do deleteItem uniques i |
if (id != i) do deleteItem uniques i |
||
)</ |
)</syntaxhighlight> |
||
=={{header|Microsoft Small Basic}}== |
|||
{{trans|Modula-2}} |
|||
<lang microsoftsmallbasic> |
|||
' Set the data. |
|||
dataArray[1] = 1 |
|||
dataArray[2] = 2 |
|||
dataArray[3] = 2 |
|||
dataArray[4] = 3 |
|||
dataArray[5] = 4 |
|||
dataArray[6] = 5 |
|||
dataArray[7] = 5 |
|||
resultArray[1] = dataArray[1] |
|||
lastResultIndex = 1 |
|||
position = 1 |
|||
While position < Array.GetItemCount(dataArray) |
|||
position = position + 1 |
|||
isNewNumber = 1 ' logical 1 |
|||
resultIndex = 1 |
|||
While (resultIndex <= lastResultIndex) And isNewNumber = 1 |
|||
If dataArray[position] = resultArray[resultIndex] Then |
|||
isNewNumber = 0 |
|||
EndIf |
|||
resultIndex = resultIndex + 1 |
|||
EndWhile |
|||
If isNewNumber = 1 Then |
|||
lastResultIndex = lastResultIndex + 1 |
|||
resultArray[lastResultIndex] = dataArray[position] |
|||
EndIf |
|||
EndWhile |
|||
For resultIndex = 1 To lastResultIndex |
|||
TextWindow.WriteLine(resultArray[resultIndex]) |
|||
EndFor |
|||
</lang> |
|||
=={{header|MiniScript}}== |
=={{header|MiniScript}}== |
||
< |
<syntaxhighlight lang="miniscript">items = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"] |
||
d = {} |
d = {} |
||
for i in items |
for i in items |
||
d.push i |
d.push i |
||
end for |
end for |
||
print d.indexes</ |
print d.indexes</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>["b", 1, "d", 3, "a", 4, "c", 2]</pre> |
<pre>["b", 1, "d", 3, "a", 4, "c", 2]</pre> |
||
Line 2,159: | Line 3,727: | ||
==={{header|mLite}}=== |
==={{header|mLite}}=== |
||
A bit like option 3, except copying each element as encountered, and checking to see if it has already been encountered |
A bit like option 3, except copying each element as encountered, and checking to see if it has already been encountered |
||
< |
<syntaxhighlight lang="ocaml">fun mem (x, []) = false |
||
| (x eql a, a :: as) = true |
| (x eql a, a :: as) = true |
||
| (x, _ :: as) = mem (x, as) |
| (x, _ :: as) = mem (x, as) |
||
Line 2,174: | Line 3,742: | ||
println ` implode ` remdup ` explode "the quick brown fox jumped over the lazy dog"; |
println ` implode ` remdup ` explode "the quick brown fox jumped over the lazy dog"; |
||
println ` remdup [1,2,3,4,4,3,2,1, "dog","cat","dog", 1.1, 2.2, 3.3, 1.1]; |
println ` remdup [1,2,3,4,4,3,2,1, "dog","cat","dog", 1.1, 2.2, 3.3, 1.1]; |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>the quickbrownfxjmpdvlazyg |
<pre>the quickbrownfxjmpdvlazyg |
||
Line 2,181: | Line 3,749: | ||
=={{header|Modula-2}}== |
=={{header|Modula-2}}== |
||
{{works with|ADW Modula-2|any (Compile with the linker option ''Console Application'').}} |
{{works with|ADW Modula-2|any (Compile with the linker option ''Console Application'').}} |
||
< |
<syntaxhighlight lang="modula2"> |
||
MODULE RemoveDuplicates; |
MODULE RemoveDuplicates; |
||
Line 2,231: | Line 3,799: | ||
END; |
END; |
||
END RemoveDuplicates. |
END RemoveDuplicates. |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|MUMPS}}== |
=={{header|MUMPS}}== |
||
<p>We'll take advantage of the fact that an array can only have one index of any specific value. Sorting into canonical order is a side effect. |
<p>We'll take advantage of the fact that an array can only have one index of any specific value. Sorting into canonical order is a side effect. |
||
If the indices are strings containing the separator string, they'll be split apart.</p>< |
If the indices are strings containing the separator string, they'll be split apart.</p><syntaxhighlight lang="mumps">REMDUPE(L,S) |
||
;L is the input listing |
;L is the input listing |
||
;S is the separator between entries |
;S is the separator between entries |
||
Line 2,245: | Line 3,813: | ||
FOR SET I=$O(Z(I)) QUIT:I="" SET R=$SELECT($L(R)=0:I,1:R_S_I) |
FOR SET I=$O(Z(I)) QUIT:I="" SET R=$SELECT($L(R)=0:I,1:R_S_I) |
||
KILL Z,I |
KILL Z,I |
||
QUIT R</ |
QUIT R</syntaxhighlight> |
||
Example:<pre>USER>W $$REMDUPE^ROSETTA("1,2,3,4,5,2,5,""HELLO"",42,""WORLD""",",") |
Example:<pre>USER>W $$REMDUPE^ROSETTA("1,2,3,4,5,2,5,""HELLO"",42,""WORLD""",",") |
||
1,2,3,4,5,42,"HELLO","WORLD"</pre> |
1,2,3,4,5,42,"HELLO","WORLD"</pre> |
||
Line 2,251: | Line 3,819: | ||
=={{header|Nanoquery}}== |
=={{header|Nanoquery}}== |
||
After executing, the list 'unique' will contain only the unique items. |
After executing, the list 'unique' will contain only the unique items. |
||
< |
<syntaxhighlight lang="nanoquery">items = {1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"} |
||
unique = {} |
unique = {} |
||
Line 2,258: | Line 3,826: | ||
unique.append(item) |
unique.append(item) |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Neko}}== |
=={{header|Neko}}== |
||
<syntaxhighlight lang="actionscript">/** |
|||
<lang ActionScript>/** |
|||
Remove duplicate elements, in Neko |
Remove duplicate elements, in Neko |
||
*/ |
*/ |
||
Line 2,284: | Line 3,852: | ||
var show = function(k, v) $print(v, " ") |
var show = function(k, v) $print(v, " ") |
||
$hiter(dedup(original), show) |
$hiter(dedup(original), show) |
||
$print("\n")</ |
$print("\n")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,293: | Line 3,861: | ||
=={{header|Nemerle}}== |
=={{header|Nemerle}}== |
||
< |
<syntaxhighlight lang="nemerle">using System.Console; |
||
module RemDups |
module RemDups |
||
Line 2,303: | Line 3,871: | ||
WriteLine(unique); |
WriteLine(unique); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|NetRexx}}== |
=={{header|NetRexx}}== |
||
This sample takes advantage of the NetRexx built-in <tt>Rexx</tt> object's indexed string capability (associative arrays). <tt>Rexx</tt> indexed strings act very like hash tables: |
This sample takes advantage of the NetRexx built-in <tt>Rexx</tt> object's indexed string capability (associative arrays). <tt>Rexx</tt> indexed strings act very like hash tables: |
||
< |
<syntaxhighlight lang="netrexx">/* NetRexx */ |
||
options replace format comments java crossref symbols nobinary |
options replace format comments java crossref symbols nobinary |
||
Line 2,354: | Line 3,922: | ||
return wordlist.space |
return wordlist.space |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,368: | Line 3,936: | ||
=={{header|NewLISP}}== |
=={{header|NewLISP}}== |
||
< |
<syntaxhighlight lang="newlisp">(unique '(1 2 3 a b c 2 3 4 b c d))</syntaxhighlight> |
||
=={{header|Nial}}== |
=={{header|Nial}}== |
||
< |
<syntaxhighlight lang="nial">uniques := [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'] |
||
cull uniques |
cull uniques |
||
=+-+-+-+-+-+-+-+-+ |
=+-+-+-+-+-+-+-+-+ |
||
=|1|2|3|a|b|c|4|d| |
=|1|2|3|a|b|c|4|d| |
||
=+-+-+-+-+-+-+-+-+</ |
=+-+-+-+-+-+-+-+-+</syntaxhighlight> |
||
Using strand form |
Using strand form |
||
< |
<syntaxhighlight lang="nial">cull 1 1 2 2 3 3 |
||
=1 2 3</ |
=1 2 3</syntaxhighlight> |
||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang="nim">import sequtils, algorithm, intsets |
||
# Go through the list, and for each element, check the rest of the list to see |
# Go through the list, and for each element, check the rest of the list to see |
||
Line 2,405: | Line 3,973: | ||
# Sort the elements and remove consecutive duplicate elements. |
# Sort the elements and remove consecutive duplicate elements. |
||
sort(items, system.cmp[int]) # O(n log n) |
sort(items, system.cmp[int]) # O(n log n) |
||
echo filterDup(items) # O(n)</ |
echo filterDup(items) # O(n)</syntaxhighlight> |
||
=={{header|Oberon-2}}== |
|||
{{trans|Modula-2}} |
|||
<syntaxhighlight lang="oberon2">MODULE RD; |
|||
IMPORT Out; |
|||
TYPE |
|||
TArray = ARRAY 7 OF INTEGER; |
|||
VAR |
|||
DataArray,ResultArray:TArray; |
|||
ResultIndex,LastResultIndex,Position:LONGINT; |
|||
IsNewNumber:BOOLEAN; |
|||
PROCEDURE Init(VAR A:TArray); |
|||
BEGIN |
|||
A[0] := 1; A[1] := 2; A[2] := 2; A[3] := 3; |
|||
A[4] := 4; A[5] := 5; A[6] := 5; |
|||
END Init; |
|||
BEGIN |
|||
Init(DataArray); |
|||
ResultArray[0] := DataArray[0]; |
|||
LastResultIndex := 0; |
|||
Position := 0; |
|||
WHILE Position < LEN(DataArray)-1 DO |
|||
INC(Position); |
|||
IsNewNumber := TRUE; |
|||
ResultIndex := 0; |
|||
WHILE(ResultIndex <= LastResultIndex) & (IsNewNumber) DO |
|||
IF DataArray[Position] = ResultArray[ResultIndex] THEN |
|||
IsNewNumber := FALSE; |
|||
END; |
|||
INC(ResultIndex); |
|||
END; |
|||
IF IsNewNumber THEN |
|||
INC(LastResultIndex); |
|||
ResultArray[LastResultIndex] := DataArray[Position]; |
|||
END; |
|||
END; |
|||
FOR ResultIndex := 0 TO LastResultIndex DO |
|||
Out.Int(ResultArray[ResultIndex],0); Out.Char(' '); |
|||
END; |
|||
Out.Ln; |
|||
END RD. |
|||
</syntaxhighlight> |
|||
=={{header|Objeck}}== |
=={{header|Objeck}}== |
||
< |
<syntaxhighlight lang="objeck"> |
||
use Structure; |
use Structure; |
||
Line 2,430: | Line 4,045: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
< |
<syntaxhighlight lang="objc">NSArray *items = [NSArray arrayWithObjects:@"A", @"B", @"C", @"B", @"A", nil]; |
||
NSSet *unique = [NSSet setWithArray:items];</ |
NSSet *unique = [NSSet setWithArray:items];</syntaxhighlight> |
||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang="ocaml">let uniq lst = |
||
let unique_set = Hashtbl.create (List.length lst) in |
let unique_set = Hashtbl.create (List.length lst) in |
||
List.iter (fun x -> Hashtbl.replace unique_set x ()) lst; |
List.iter (fun x -> Hashtbl.replace unique_set x ()) lst; |
||
Line 2,444: | Line 4,059: | ||
let _ = |
let _ = |
||
uniq [1;2;3;2;3;4]</ |
uniq [1;2;3;2;3;4]</syntaxhighlight> |
||
Another solution (preserves order of first occurrence): |
Another solution (preserves order of first occurrence): |
||
< |
<syntaxhighlight lang="ocaml">let uniq lst = |
||
let seen = Hashtbl.create (List.length lst) in |
let seen = Hashtbl.create (List.length lst) in |
||
List.filter (fun x -> let tmp = not (Hashtbl.mem seen x) in |
List.filter (fun x -> let tmp = not (Hashtbl.mem seen x) in |
||
Line 2,454: | Line 4,069: | ||
let _ = |
let _ = |
||
uniq [1;2;3;2;3;4]</ |
uniq [1;2;3;2;3;4]</syntaxhighlight> |
||
Solution reversing list order : |
Solution reversing list order : |
||
< |
<syntaxhighlight lang="ocaml">let uniq l = |
||
let rec tail_uniq a l = |
let rec tail_uniq a l = |
||
match l with |
match l with |
||
| [] -> a |
| [] -> a |
||
| hd::tl -> tail_uniq (hd::a) (List.filter (fun x -> x != hd) tl) in |
| hd::tl -> tail_uniq (hd::a) (List.filter (fun x -> x != hd) tl) in |
||
tail_uniq [] l</ |
tail_uniq [] l</syntaxhighlight> |
||
{{works with|OCaml|4.02+}} |
{{works with|OCaml|4.02+}} |
||
< |
<syntaxhighlight lang="ocaml">List.sort_uniq compare [1;2;3;2;3;4]</syntaxhighlight> |
||
=={{header|Octave}}== |
=={{header|Octave}}== |
||
< |
<syntaxhighlight lang="octave"> |
||
input=[1 2 6 4 2 32 5 5 4 3 3 5 1 2 32 4 4]; |
input=[1 2 6 4 2 32 5 5 4 3 3 5 1 2 32 4 4]; |
||
output=unique(input); |
output=unique(input); |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Oforth}}== |
=={{header|Oforth}}== |
||
Line 2,486: | Line 4,101: | ||
=={{header|ooRexx}}== |
=={{header|ooRexx}}== |
||
< |
<syntaxhighlight lang="oorexx">data = .array~of(1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d") |
||
uniqueData = .set~new~union(data)~makearray~sort |
uniqueData = .set~new~union(data)~makearray~sort |
||
Line 2,493: | Line 4,108: | ||
do item over uniqueData |
do item over uniqueData |
||
say item |
say item |
||
end</ |
end</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Unique elements are |
<pre>Unique elements are |
||
Line 2,509: | Line 4,124: | ||
The following solutions only works if the value type is allowed as a key in a dictionary. |
The following solutions only works if the value type is allowed as a key in a dictionary. |
||
< |
<syntaxhighlight lang="oz">declare |
||
fun {Nub Xs} |
fun {Nub Xs} |
||
Line 2,520: | Line 4,135: | ||
in |
in |
||
{Show {Nub [1 2 1 3 5 4 3 4 4]}}</ |
{Show {Nub [1 2 1 3 5 4 3 4 4]}}</syntaxhighlight> |
||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
Sort and remove duplicates. Other methods should be implemented as well. |
Sort and remove duplicates. Other methods should be implemented as well. |
||
< |
<syntaxhighlight lang="parigp">rd(v)={ |
||
vecsort(v,,8) |
vecsort(v,,8) |
||
};</ |
};</syntaxhighlight> |
||
=={{header|Pascal}}== |
=={{header|Pascal}}== |
||
< |
<syntaxhighlight lang="pascal">Program RemoveDuplicates; |
||
const |
const |
||
Line 2,561: | Line 4,176: | ||
for i := low(rArray) to last do |
for i := low(rArray) to last do |
||
writeln (rArray[i]); |
writeln (rArray[i]); |
||
end.</ |
end.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>% ./RemoveDuplicates |
<pre>% ./RemoveDuplicates |
||
Line 2,569: | Line 4,184: | ||
4 |
4 |
||
5</pre> |
5</pre> |
||
=={{header|PascalABC.NET}}== |
|||
<syntaxhighlight lang="delphi"> |
|||
begin |
|||
// By algorithm |
|||
var nums := Arr(1, 1, 2, 3, 4, 4); |
|||
var unique := new List<integer>; |
|||
foreach var x in nums do |
|||
if x not in unique then |
|||
unique.Add(x); |
|||
unique.Println; |
|||
// By method |
|||
var unique2 := nums.Distinct; |
|||
unique2.Println; |
|||
// Using hash set |
|||
var unique3 := HSet(nums); |
|||
unique3.Println; |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 2 3 4 |
|||
1 2 3 4 |
|||
1 2 3 4 |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
{{libheader|List::MoreUtils}} |
{{libheader|List::MoreUtils}} |
||
(this version even preserves the order of first appearance of each element) |
(this version even preserves the order of first appearance of each element) |
||
< |
<syntaxhighlight lang="perl">use List::MoreUtils qw(uniq); |
||
my @uniq = uniq qw(1 2 3 a b c 2 3 4 b c d);</ |
my @uniq = uniq qw(1 2 3 a b c 2 3 4 b c d);</syntaxhighlight> |
||
It is implemented like this: |
It is implemented like this: |
||
< |
<syntaxhighlight lang="perl">my %seen; |
||
my @uniq = grep {!$seen{$_}++} qw(1 2 3 a b c 2 3 4 b c d);</ |
my @uniq = grep {!$seen{$_}++} qw(1 2 3 a b c 2 3 4 b c d);</syntaxhighlight> |
||
Note: the following two solutions convert elements to strings in the result, so if you give it references they will lose the ability to be dereferenced. |
Note: the following two solutions convert elements to strings in the result, so if you give it references they will lose the ability to be dereferenced. |
||
Alternately: |
Alternately: |
||
< |
<syntaxhighlight lang="perl">my %hash = map { $_ => 1 } qw(1 2 3 a b c 2 3 4 b c d); |
||
my @uniq = keys %hash;</ |
my @uniq = keys %hash;</syntaxhighlight> |
||
Alternately: |
Alternately: |
||
< |
<syntaxhighlight lang="perl">my %seen; |
||
@seen{qw(1 2 3 a b c 2 3 4 b c d)} = (); |
@seen{qw(1 2 3 a b c 2 3 4 b c d)} = (); |
||
my @uniq = keys %seen;</ |
my @uniq = keys %seen;</syntaxhighlight> |
||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Standard builtin. The "STABLE" option preserves order of first occurence. Applies to any data type. The default option for unique(), "SORT", obviously produces sorted output, and there is one other recognised option, "PRESORTED", which can be used either to avoid an unnecessary sort, or to only remove adjacent duplicates. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<lang Phix>sequence test |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">unique</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Now is the time for all good men to come to the aid of the party."</span><span style="color: #0000FF;">),</span><span style="color: #008000;">"STABLE"</span><span style="color: #0000FF;">))</span> |
|||
function alpha(integer i, integer j) |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">unique</span><span style="color: #0000FF;">({</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">15</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"STABLE"</span><span style="color: #0000FF;">)</span> |
|||
integer res |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">unique</span><span style="color: #0000FF;">({</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"a"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"b"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"c"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"b"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"c"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"d"</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"STABLE"</span><span style="color: #0000FF;">)</span> |
|||
res = compare(test[i],test[j]) |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">unique</span><span style="color: #0000FF;">({</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"STABLE"</span><span style="color: #0000FF;">)</span> |
|||
if res=0 then |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">unique</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"chthonic eleemosynary paronomasiac"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"STABLE"</span><span style="color: #0000FF;">)</span> |
|||
res = compare(i,j) |
|||
<!--</syntaxhighlight>--> |
|||
end if |
|||
return res |
|||
end function |
|||
function unique(sequence s) |
|||
sequence at, valid = repeat(1,length(s)) |
|||
object last, this |
|||
integer ai, nxt |
|||
test = s |
|||
at = custom_sort(routine_id("alpha"),tagset(length(test))) |
|||
last = test[at[1]] |
|||
for i=2 to length(at) do |
|||
ai = at[i] |
|||
this = test[ai] |
|||
valid[ai] = last!=this |
|||
last = this |
|||
end for |
|||
nxt = find(0,valid) |
|||
if nxt then |
|||
for i=nxt+1 to length(test) do |
|||
if valid[i] then |
|||
test[nxt] = test[i] |
|||
nxt += 1 |
|||
end if |
|||
end for |
|||
test = test[1..nxt-1] |
|||
end if |
|||
return test |
|||
end function |
|||
?join(unique(split("Now is the time for all good men to come to the aid of the party."))) |
|||
?unique({1, 2, 1, 4, 5, 2, 15, 1, 3, 4}) |
|||
?unique({1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"}) |
|||
?unique({1,3,2,9,1,2,3,8,8,1,0,2}) |
|||
?unique("chthonic eleemosynary paronomasiac")</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,648: | Line 4,253: | ||
=={{header|Phixmonti}}== |
=={{header|Phixmonti}}== |
||
< |
<syntaxhighlight lang="phixmonti">"Now" "is" "the" "time" "for" "all" "good" "men" "to" "come" "to" "the" "aid" "of" "the" "party." stklen tolist |
||
0 tolist var newlist |
0 tolist var newlist |
||
Line 2,661: | Line 4,266: | ||
endfor |
endfor |
||
newlist print drop</ |
newlist print drop</syntaxhighlight> |
||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
< |
<syntaxhighlight lang="php">$list = array(1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'); |
||
$unique_list = array_unique($list);</ |
$unique_list = array_unique($list);</syntaxhighlight> |
||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
There is a built-in function |
There is a built-in function |
||
< |
<syntaxhighlight lang="picolisp">(uniq (2 4 6 1 2 3 4 5 6 1 3 5))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>-> (2 4 6 1 3 5)</pre> |
<pre>-> (2 4 6 1 3 5)</pre> |
||
=={{header|PL/I}}== |
=={{header|PL/I}}== |
||
< |
<syntaxhighlight lang="pl/i">*process mar(1,72); |
||
remdup: Proc options(main); |
remdup: Proc options(main); |
||
declare t(20) fixed initial (6, 6, 1, 5, 6, 2, 1, 7, |
declare t(20) fixed initial (6, 6, 1, 5, 6, 2, 1, 7, |
||
Line 2,696: | Line 4,301: | ||
put skip list ('Unique elements are:'); |
put skip list ('Unique elements are:'); |
||
put edit ((t(k) do k = 1 to i)) (skip,20(f(3))); |
put edit ((t(k) do k = 1 to i)) (skip,20(f(3))); |
||
end;</ |
end;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Input: |
<pre>Input: |
||
Line 2,705: | Line 4,310: | ||
=={{header|Pop11}}== |
=={{header|Pop11}}== |
||
< |
<syntaxhighlight lang="pop11">;;; Initial array |
||
lvars ar = {1 2 3 2 3 4}; |
lvars ar = {1 2 3 2 3 4}; |
||
;;; Create a hash table |
;;; Create a hash table |
||
Line 2,717: | Line 4,322: | ||
;;; Collect keys into a list |
;;; Collect keys into a list |
||
lvars ls = []; |
lvars ls = []; |
||
appdata(ht, procedure(x); cons(front(x), ls) -> ls; endprocedure);</ |
appdata(ht, procedure(x); cons(front(x), ls) -> ls; endprocedure);</syntaxhighlight> |
||
=={{header|PostScript}}== |
=={{header|PostScript}}== |
||
{{libheader|initlib}} |
{{libheader|initlib}} |
||
< |
<syntaxhighlight lang="postscript"> |
||
[10 8 8 98 32 2 4 5 10 ] dup length dict begin aload let* currentdict {pop} map end |
[10 8 8 98 32 2 4 5 10 ] dup length dict begin aload let* currentdict {pop} map end |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|PowerShell}}== |
=={{header|PowerShell}}== |
||
The common array for both approaches: |
The common array for both approaches: |
||
< |
<syntaxhighlight lang="powershell">$data = 1,2,3,1,2,3,4,1</syntaxhighlight> |
||
Using a hash table to remove duplicates: |
Using a hash table to remove duplicates: |
||
< |
<syntaxhighlight lang="powershell">$h = @{} |
||
foreach ($x in $data) { |
foreach ($x in $data) { |
||
$h[$x] = 1 |
$h[$x] = 1 |
||
} |
} |
||
$h.Keys</ |
$h.Keys</syntaxhighlight> |
||
Sorting and removing duplicates along the way can be done with the <code>Sort-Object</code> cmdlet. |
Sorting and removing duplicates along the way can be done with the <code>Sort-Object</code> cmdlet. |
||
< |
<syntaxhighlight lang="powershell">$data | Sort-Object -Unique</syntaxhighlight> |
||
Removing duplicates without sorting can be done with the <code>Select-Object</code> cmdlet. |
Removing duplicates without sorting can be done with the <code>Select-Object</code> cmdlet. |
||
< |
<syntaxhighlight lang="powershell">$data | Select-Object -Unique</syntaxhighlight> |
||
=={{header|Prolog}}== |
=={{header|Prolog}}== |
||
< |
<syntaxhighlight lang="prolog">uniq(Data,Uniques) :- sort(Data,Uniques).</syntaxhighlight> |
||
Example usage: |
Example usage: |
||
< |
<syntaxhighlight lang="prolog">?- uniq([1, 2, 3, 2, 3, 4],Xs). |
||
Xs = [1, 2, 3, 4]</ |
Xs = [1, 2, 3, 4]</syntaxhighlight> |
||
Because sort/2 is GNU prolog and not ISO here is an ISO compliant version: |
Because sort/2 is GNU prolog and not ISO here is an ISO compliant version: |
||
< |
<syntaxhighlight lang="prolog">member1(X,[H|_]) :- X==H,!. |
||
member1(X,[_|T]) :- member1(X,T). |
member1(X,[_|T]) :- member1(X,T). |
||
distinct([],[]). |
distinct([],[]). |
||
distinct([H|T],C) :- member1(H,T),!, distinct(T,C). |
distinct([H|T],C) :- member1(H,T),!, distinct(T,C). |
||
distinct([H|T],[H|C]) :- distinct(T,C).</ |
distinct([H|T],[H|C]) :- distinct(T,C).</syntaxhighlight> |
||
Example usage: |
Example usage: |
||
< |
<syntaxhighlight lang="prolog">?- distinct([A, A, 1, 2, 3, 2, 3, 4],Xs). |
||
Xs = [A, 1, 2, 3, 4]</ |
Xs = [A, 1, 2, 3, 4]</syntaxhighlight> |
||
=={{header|PureBasic}}== |
|||
Task solved with the built in Hash Table which are called Maps in PureBasic |
|||
<lang PureBasic>NewMap MyElements.s() |
|||
For i=0 To 9 ;Mark 10 items at random, causing high risk of duplication items. |
|||
x=Random(9) |
|||
t$="Number "+str(x)+" is marked" |
|||
MyElements(str(x))=t$ ; Add element 'X' to the hash list or overwrite if already included. |
|||
Next |
|||
ForEach MyElements() |
|||
Debug MyElements() |
|||
Next</lang> |
|||
Output may look like this, e.g. duplicated items are automatically removed as they have the same hash value. |
|||
Number 0 is marked |
|||
Number 2 is marked |
|||
Number 5 is marked |
|||
Number 6 is marked |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
If all the elements are ''hashable'' (this excludes ''list'', ''dict'', ''set'', and other mutable types), we can use a <tt>set</tt>: |
If all the elements are ''hashable'' (this excludes ''list'', ''dict'', ''set'', and other mutable types), we can use a <tt>set</tt>: |
||
< |
<syntaxhighlight lang="python">items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'] |
||
unique = list(set(items))</ |
unique = list(set(items))</syntaxhighlight> |
||
or if we want to keep the order of the elements |
or if we want to keep the order of the elements |
||
< |
<syntaxhighlight lang="python">items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'] |
||
unique = [] |
unique = [] |
||
helperset = set() |
helperset = set() |
||
Line 2,791: | Line 4,377: | ||
if x not in helperset: |
if x not in helperset: |
||
unique.append(x) |
unique.append(x) |
||
helperset.add(x)</ |
helperset.add(x)</syntaxhighlight> |
||
If all the elements are comparable (i.e. <, >=, etc. operators; this works for ''list'', ''dict'', etc. but not for ''complex'' and many other types, including most user-defined types), we can sort and group: |
If all the elements are comparable (i.e. <, >=, etc. operators; this works for ''list'', ''dict'', etc. but not for ''complex'' and many other types, including most user-defined types), we can sort and group: |
||
< |
<syntaxhighlight lang="python">import itertools |
||
items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'] |
items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'] |
||
unique = [k for k,g in itertools.groupby(sorted(items))]</ |
unique = [k for k,g in itertools.groupby(sorted(items))]</syntaxhighlight> |
||
If both of the above fails, we have to use the brute-force method, which is inefficient: |
If both of the above fails, we have to use the brute-force method, which is inefficient: |
||
< |
<syntaxhighlight lang="python">items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd'] |
||
unique = [] |
unique = [] |
||
for x in items: |
for x in items: |
||
if x not in unique: |
if x not in unique: |
||
unique.append(x)</ |
unique.append(x)</syntaxhighlight> |
||
another way of removing duplicate elements from a list, while preserving the order would be to use OrderedDict module like so |
another way of removing duplicate elements from a list, while preserving the order would be to use OrderedDict module like so |
||
< |
<syntaxhighlight lang="python"> |
||
from collections import OrderedDict as od |
from collections import OrderedDict as od |
||
print(list(od.fromkeys([1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']).keys())) |
print(list(od.fromkeys([1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']).keys())) |
||
</syntaxhighlight> |
|||
</lang> |
|||
See also http://www.peterbe.com/plog/uniqifiers-benchmark and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 |
See also http://www.peterbe.com/plog/uniqifiers-benchmark and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 |
||
Line 2,819: | Line 4,405: | ||
One way to do this is to require an equality predicate, or perhaps a key function, in addition to a list to be pruned. For example, using itertools.groupby, at the cost of needing a sort and discarding order: |
One way to do this is to require an equality predicate, or perhaps a key function, in addition to a list to be pruned. For example, using itertools.groupby, at the cost of needing a sort and discarding order: |
||
< |
<syntaxhighlight lang="python">from itertools import (groupby) |
||
Line 2,840: | Line 4,426: | ||
print ( |
print ( |
||
nubByKey(k, xs) |
nubByKey(k, xs) |
||
)</ |
)</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>['apple', 'aPPLE', 'Apple', 'orange', 'ORANGE', 'Orange', 'ampersand'] |
<pre>['apple', 'aPPLE', 'Apple', 'orange', 'ORANGE', 'Orange', 'ampersand'] |
||
Line 2,849: | Line 4,435: | ||
Or alternatively, using an equality predicate with a recursive function which scales less well, but does preserve order: |
Or alternatively, using an equality predicate with a recursive function which scales less well, but does preserve order: |
||
< |
<syntaxhighlight lang="python"># nubByEq :: (a -> a -> Bool) -> [a] -> [a] |
||
def nubByEq(eq, xs): |
def nubByEq(eq, xs): |
||
def go(yys, xxs): |
def go(yys, xxs): |
||
Line 2,886: | Line 4,472: | ||
print ( |
print ( |
||
nubByEq(eq, xs) |
nubByEq(eq, xs) |
||
)</ |
)</syntaxhighlight> |
||
A briefer definition of which might be in terms of ''filter'': |
A briefer definition of which might be in terms of ''filter'': |
||
< |
<syntaxhighlight lang="python"># nubBy :: (a -> a -> Bool) -> [a] -> [a] |
||
def nubBy(p, xs): |
def nubBy(p, xs): |
||
def go(xs): |
def go(xs): |
||
Line 2,902: | Line 4,488: | ||
else: |
else: |
||
return [] |
return [] |
||
return go(xs)</ |
return go(xs)</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
Line 2,912: | Line 4,498: | ||
=={{header|Qi}}== |
=={{header|Qi}}== |
||
<syntaxhighlight lang="qi"> |
|||
<lang qi> |
|||
(define remove-duplicates |
(define remove-duplicates |
||
[] -> [] |
[] -> [] |
||
Line 2,919: | Line 4,505: | ||
(remove-duplicates [a b a a b b c d e]) |
(remove-duplicates [a b a a b b c d e]) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Quackery}}== |
=={{header|Quackery}}== |
||
Line 2,930: | Line 4,516: | ||
a nest of strings sorted in descending order. |
a nest of strings sorted in descending order. |
||
< |
<syntaxhighlight lang="quackery"> [ dup [] = iff ]else[ done |
||
' sortwith nested |
' sortwith nested |
||
]'[ nested join do |
]'[ nested join do |
||
Line 2,940: | Line 4,526: | ||
drop ] is uniquewith ( [ --> [ ) |
drop ] is uniquewith ( [ --> [ ) |
||
' [ 1 2 3 5 6 7 8 1 2 3 4 5 6 7 ] uniquewith > echo</ |
' [ 1 2 3 5 6 7 8 1 2 3 4 5 6 7 ] uniquewith > echo</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,948: | Line 4,534: | ||
=={{header|R}}== |
=={{header|R}}== |
||
< |
<syntaxhighlight lang="r">items <- c(1,2,3,2,4,3,2) |
||
unique (items)</ |
unique (items)</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
Using the built-in function |
Using the built-in function |
||
<syntaxhighlight lang="racket"> |
|||
<lang Racket> |
|||
-> (remove-duplicates '(2 1 3 2.0 a 4 5 b 4 3 a 7 1 3 x 2)) |
-> (remove-duplicates '(2 1 3 2.0 a 4 5 b 4 3 a 7 1 3 x 2)) |
||
'(2 1 3 2.0 a 4 5 b 7 x) |
'(2 1 3 2.0 a 4 5 b 7 x) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Using a hash-table: |
Using a hash-table: |
||
<syntaxhighlight lang="racket"> |
|||
<lang Racket> |
|||
(define (unique/hash lst) |
(define (unique/hash lst) |
||
(hash-keys (for/hash ([x (in-list lst)]) (values x #t)))) |
(hash-keys (for/hash ([x (in-list lst)]) (values x #t)))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Using a set: |
Using a set: |
||
<syntaxhighlight lang="racket"> |
|||
<lang Racket> |
|||
(define unique/set (compose1 set->list list->set)) |
(define unique/set (compose1 set->list list->set)) |
||
</syntaxhighlight> |
|||
</lang> |
|||
A definition that works with arbitrary sequences and allows |
A definition that works with arbitrary sequences and allows |
||
specification of an equality predicate. |
specification of an equality predicate. |
||
<syntaxhighlight lang="racket"> |
|||
<lang Racket> |
|||
(define (unique seq #:same-test [same? equal?]) |
(define (unique seq #:same-test [same? equal?]) |
||
(for/fold ([res '()]) |
(for/fold ([res '()]) |
||
([x seq] #:unless (memf (curry same? x) res)) |
([x seq] #:unless (memf (curry same? x) res)) |
||
(cons x res))) |
(cons x res))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
<pre> |
<pre> |
||
-> (unique '(2 1 3 2.0 a 4 5 b 4 3 a 7 1 3 x 2)) |
-> (unique '(2 1 3 2.0 a 4 5 b 4 3 a 7 1 3 x 2)) |
||
Line 2,992: | Line 4,578: | ||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
(formerly Perl 6) |
(formerly Perl 6) |
||
<lang |
<syntaxhighlight lang="raku" line>my @unique = [1, 2, 3, 5, 2, 4, 3, -3, 7, 5, 6].unique;</syntaxhighlight> |
||
Or just make a set of it. |
Or just make a set of it. |
||
<lang |
<syntaxhighlight lang="raku" line>set(1,2,3,5,2,4,3,-3,7,5,6).list</syntaxhighlight> |
||
=={{header|Raven}}== |
=={{header|Raven}}== |
||
< |
<syntaxhighlight lang="raven">[ 1 2 3 'a' 'b' 'c' 2 3 4 'b' 'c' 'd' ] as items |
||
items copy unique print |
items copy unique print |
||
Line 3,009: | Line 4,595: | ||
5 => "c" |
5 => "c" |
||
6 => 4 |
6 => 4 |
||
7 => "d"</ |
7 => "d"</syntaxhighlight> |
||
=={{header|REBOL}}== |
=={{header|REBOL}}== |
||
< |
<syntaxhighlight lang="rebol">print mold unique [1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,018: | Line 4,604: | ||
=={{header|Red}}== |
=={{header|Red}}== |
||
< |
<syntaxhighlight lang="red">>> items: [1 "a" "c" 1 3 4 5 "c" 3 4 5] |
||
>> unique items |
>> unique items |
||
== [1 "a" "c" 3 4 5]</ |
== [1 "a" "c" 3 4 5]</syntaxhighlight> |
||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Line 3,034: | Line 4,620: | ||
===version 1, using method 1=== |
===version 1, using method 1=== |
||
< |
<syntaxhighlight lang="rexx">/*REXX program removes any duplicate elements (items) that are in a list (using a hash).*/ |
||
$= '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' /*item list.*/ |
$= '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' /*item list.*/ |
||
say 'original list:' $ |
say 'original list:' $ |
||
Line 3,044: | Line 4,630: | ||
say |
say |
||
say 'modified list:' space(z) /*stick a fork in it, we're all done. */ |
say 'modified list:' space(z) /*stick a fork in it, we're all done. */ |
||
say right( words(z), 17, '─') 'words in the modified list.'</ |
say right( words(z), 17, '─') 'words in the modified list.'</syntaxhighlight> |
||
{{out|output|text= when using the default input list:}} |
{{out|output|text= when using the default input list:}} |
||
<pre> |
<pre> |
||
Line 3,058: | Line 4,644: | ||
Sorting of the list elements isn't necessary. |
Sorting of the list elements isn't necessary. |
||
< |
<syntaxhighlight lang="rexx">/*REXX program removes any duplicate elements (items) that are in a list (using a list).*/ |
||
$= '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' /*item list.*/ |
$= '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' /*item list.*/ |
||
say 'original list:' $ |
say 'original list:' $ |
||
Line 3,068: | Line 4,654: | ||
say |
say |
||
say 'modified list:' space($) /*stick a fork in it, we're all done. */ |
say 'modified list:' space($) /*stick a fork in it, we're all done. */ |
||
say right( words(z), 17, '─') 'words in the modified list.'</ |
say right( words(z), 17, '─') 'words in the modified list.'</syntaxhighlight> |
||
{{out|output|text= is identical to the 1<sup>st</sup> REXX version.}} <br><br> |
{{out|output|text= is identical to the 1<sup>st</sup> REXX version.}} <br><br> |
||
===version 3, using method 3=== |
===version 3, using method 3=== |
||
< |
<syntaxhighlight lang="rexx">/*REXX program removes any duplicate elements (items) that are in a list (using 2 lists)*/ |
||
old = '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' |
old = '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' |
||
say 'original list:' old |
say 'original list:' old |
||
Line 3,082: | Line 4,668: | ||
say |
say |
||
say 'modified list:' space(new) /*stick a fork in it, we're all done. */ |
say 'modified list:' space(new) /*stick a fork in it, we're all done. */ |
||
say right( words(new), 17, '─') 'words in the modified list.'</ |
say right( words(new), 17, '─') 'words in the modified list.'</syntaxhighlight> |
||
{{out|output|text= is identical to the 1<sup>st</sup> REXX version.}} <br><br> |
{{out|output|text= is identical to the 1<sup>st</sup> REXX version.}} <br><br> |
||
===version 4, using method 1 (hash table) via REXX stems=== |
===version 4, using method 1 (hash table) via REXX stems=== |
||
< |
<syntaxhighlight lang="rexx">/* REXX ************************************************************ |
||
* 26.11.2012 Walter Pachl |
* 26.11.2012 Walter Pachl |
||
* added: show multiple occurrences |
* added: show multiple occurrences |
||
Line 3,113: | Line 4,699: | ||
If count.w>1 Then |
If count.w>1 Then |
||
Say right(count.w,3) w |
Say right(count.w,3) w |
||
End</ |
End</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 3,129: | Line 4,715: | ||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang="ring"> |
||
list = ["Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "to", "the", "aid", "of", "the", "party."] |
list = ["Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "to", "the", "aid", "of", "the", "party."] |
||
for i = 1 to len(list) |
for i = 1 to len(list) |
||
Line 3,141: | Line 4,727: | ||
next |
next |
||
see nl |
see nl |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Now is the time for all good men to come aid of party. |
Now is the time for all good men to come aid of party. |
||
</pre> |
|||
=={{header|RPL}}== |
|||
We follow here a fourth way, which requires few words and take advantage of the (relative) speed of the <code>POS</code> function. |
|||
{{works with|Halcyon Calc|4.2.8}} |
|||
{| class="wikitable" |
|||
! RPL code |
|||
! Comment |
|||
|- |
|||
| |
|||
≪ → input |
|||
≪ { } |
|||
1 input SIZE '''FOR''' j |
|||
input j GET |
|||
'''IF''' DUP2 POS '''THEN''' DROP '''ELSE''' + '''END ''' |
|||
'''NEXT''' |
|||
≫ ≫ ‘'''NODUP'''’ STO |
|||
| |
|||
'''NODUP''' ''( { a b a...c } -- { a b..c } ) '' |
|||
Initialize output list |
|||
Go through input list |
|||
If input[j] already in output list |
|||
then forget it else add it to output list |
|||
End loop |
|||
|} |
|||
{ 1 2 3 'a' 'b' 'c' 2 3 4 'b' 'c' 'd' } '''NODUP''' |
|||
{{out}} |
|||
<pre> |
|||
1: { 1 2 3 'a' 'b' 'c' 4 'd' } |
|||
</pre> |
</pre> |
||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
Ruby has an <code>Array#uniq</code> built-in method, which returns a new array by removing duplicate values in self. |
Ruby has an <code>Array#uniq</code> built-in method, which returns a new array by removing duplicate values in self. |
||
< |
<syntaxhighlight lang="ruby">ary = [1,1,2,1,'redundant',[1,2,3],[1,2,3],'redundant'] |
||
p ary.uniq # => [1, 2, "redundant", [1, 2, 3]]</ |
p ary.uniq # => [1, 2, "redundant", [1, 2, 3]]</syntaxhighlight> |
||
You can also write your own uniq method. |
You can also write your own uniq method. |
||
< |
<syntaxhighlight lang="ruby">class Array |
||
# used Hash |
# used Hash |
||
def uniq1 |
def uniq1 |
||
Line 3,178: | Line 4,794: | ||
p ary.uniq1 #=> [1, 2, 3, 7, 6, 5, 4] |
p ary.uniq1 #=> [1, 2, 3, 7, 6, 5, 4] |
||
p ary.uniq2 #=> [1, 2, 3, 4, 5, 6, 7] |
p ary.uniq2 #=> [1, 2, 3, 4, 5, 6, 7] |
||
p ary.uniq3 #=> [1, 2, 3, 7, 6, 5, 4]</ |
p ary.uniq3 #=> [1, 2, 3, 7, 6, 5, 4]</syntaxhighlight> |
||
A version without implementing class declarations: |
A version without implementing class declarations: |
||
< |
<syntaxhighlight lang="ruby">def unique(array) |
||
pure = Array.new |
pure = Array.new |
||
for i in array |
for i in array |
||
Line 3,194: | Line 4,810: | ||
unique ["hi","hey","hello","hi","hey","heyo"] # => ["hi", "hey", "hello", "heyo"] |
unique ["hi","hey","hello","hi","hey","heyo"] # => ["hi", "hey", "hello", "heyo"] |
||
unique [1,2,3,4,1,2,3,5,1,2,3,4,5] # => [1,2,3,4,5]</ |
unique [1,2,3,4,1,2,3,5,1,2,3,4,5] # => [1,2,3,4,5]</syntaxhighlight> |
||
=={{header|Run BASIC}}== |
|||
<lang runbasic>a$ = "2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2" |
|||
for i = 1 to len(a$) |
|||
a1$ = word$(a$,i) |
|||
if a1$ = "" then exit for |
|||
for i1 = 1 to len(b$) |
|||
if a1$ = word$(b$,i1) then [nextWord] |
|||
next i1 |
|||
b$ = b$ + a1$ + " " |
|||
[nextWord] |
|||
next i |
|||
print "Dups:";a$ |
|||
print "No Dups:";b$</lang> |
|||
<pre>Dups:2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2 |
|||
No Dups:2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 0 4.4 </pre> |
|||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
< |
<syntaxhighlight lang="rust">use std::collections::HashSet; |
||
use std::hash::Hash; |
use std::hash::Hash; |
||
Line 3,233: | Line 4,831: | ||
remove_duplicate_elements_sorting(&mut sample_elements); |
remove_duplicate_elements_sorting(&mut sample_elements); |
||
println!("After removal of duplicates : {:?}", sample_elements); |
println!("After removal of duplicates : {:?}", sample_elements); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 3,241: | Line 4,839: | ||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
< |
<syntaxhighlight lang="scala">val list = List(1,2,3,4,2,3,4,99) |
||
val l2 = list.distinct |
val l2 = list.distinct |
||
// l2: scala.List[scala.Int] = List(1,2,3,4,99) |
// l2: scala.List[scala.Int] = List(1,2,3,4,99) |
||
Line 3,248: | Line 4,846: | ||
val arr2 = arr.distinct |
val arr2 = arr.distinct |
||
// arr2: Array[Int] = Array(1, 2, 3, 4, 99) |
// arr2: Array[Int] = Array(1, 2, 3, 4, 99) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Scheme}}== |
=={{header|Scheme}}== |
||
< |
<syntaxhighlight lang="scheme">(define (remove-duplicates l) |
||
(cond ((null? l) |
(cond ((null? l) |
||
'()) |
'()) |
||
Line 3,259: | Line 4,857: | ||
(cons (car l) (remove-duplicates (cdr l)))))) |
(cons (car l) (remove-duplicates (cdr l)))))) |
||
(remove-duplicates '(1 2 1 3 2 4 5))</ |
(remove-duplicates '(1 2 1 3 2 4 5))</syntaxhighlight> |
||
< |
<syntaxhighlight lang="scheme">(1 3 2 4 5)</syntaxhighlight> |
||
Alternative approach: |
Alternative approach: |
||
< |
<syntaxhighlight lang="scheme">(define (remove-duplicates l) |
||
(do ((a '() (if (member (car l) a) a (cons (car l) a))) |
(do ((a '() (if (member (car l) a) a (cons (car l) a))) |
||
(l l (cdr l))) |
(l l (cdr l))) |
||
((null? l) (reverse a)))) |
((null? l) (reverse a)))) |
||
(remove-duplicates '(1 2 1 3 2 4 5))</ |
(remove-duplicates '(1 2 1 3 2 4 5))</syntaxhighlight> |
||
< |
<syntaxhighlight lang="scheme">(1 2 3 4 5)</syntaxhighlight> |
||
The function 'delete-duplicates' is also available in srfi-1. |
The function 'delete-duplicates' is also available in srfi-1. |
||
=={{header|Seed7}}== |
=={{header|Seed7}}== |
||
< |
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
||
const proc: main is func |
const proc: main is func |
||
Line 3,288: | Line 4,886: | ||
end for; |
end for; |
||
writeln(dataSet); |
writeln(dataSet); |
||
end func;</ |
end func;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,296: | Line 4,894: | ||
=={{header|SETL}}== |
=={{header|SETL}}== |
||
< |
<syntaxhighlight lang="setl">items := [0,7,6,6,4,9,7,1,2,3,2]; |
||
print(unique(items));</ |
print(unique(items));</syntaxhighlight> |
||
Output in arbitrary order (convert tuple->set then set->tuple): |
Output in arbitrary order (convert tuple->set then set->tuple): |
||
< |
<syntaxhighlight lang="setl">proc unique(items); |
||
return [item: item in {item: item in items}]; |
return [item: item in {item: item in items}]; |
||
end proc;</ |
end proc;</syntaxhighlight> |
||
Preserving source order |
Preserving source order |
||
< |
<syntaxhighlight lang="setl">proc unique(items); |
||
seen := {}; |
seen := {}; |
||
return [item: item in items, nps in {#seen} | #(seen with:= item) > nps]; |
return [item: item in items, nps in {#seen} | #(seen with:= item) > nps]; |
||
end proc;</ |
end proc;</syntaxhighlight> |
||
< |
<syntaxhighlight lang="setl">proc unique(items); |
||
seen := {}; |
seen := {}; |
||
return [item: item in items, nps in {#seen} | #(seen with:= item) > nps]; |
return [item: item in items, nps in {#seen} | #(seen with:= item) > nps]; |
||
end proc;</ |
end proc;</syntaxhighlight> |
||
< |
<syntaxhighlight lang="setl">items := [0,7,6,6,4,9,7,1,2,3,2]; |
||
print(unique(items));</ |
print(unique(items));</syntaxhighlight> |
||
Output in arbitrary order (convert tuple->set then set->tuple): |
Output in arbitrary order (convert tuple->set then set->tuple): |
||
< |
<syntaxhighlight lang="setl">proc unique(items); |
||
return [item: item in {item: item in items}]; |
return [item: item in {item: item in items}]; |
||
end proc;</ |
end proc;</syntaxhighlight> |
||
=={{header|SETL4}}== |
=={{header|SETL4}}== |
||
<syntaxhighlight lang="setl4"> |
|||
<lang SETL4> |
|||
set = new('set') |
set = new('set') |
||
* Add all the elements of the array to the set. |
* Add all the elements of the array to the set. |
||
add(set,array) |
add(set,array) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
< |
<syntaxhighlight lang="ruby">var ary = [1,1,2,1,'redundant',[1,2,3],[1,2,3],'redundant']; |
||
say ary.uniq.dump; |
say ary.uniq.dump; |
||
say ary.last_uniq.dump;</ |
say ary.last_uniq.dump;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[1, 2, 'redundant', [1, 2, 3]] |
<pre>[1, 2, 'redundant', [1, 2, 3]] |
||
Line 3,339: | Line 4,937: | ||
=={{header|Slate}}== |
=={{header|Slate}}== |
||
< |
<syntaxhighlight lang="slate">[|:s| #(1 2 3 4 1 2 3 4) >> s] writingAs: Set. |
||
"==> {"Set traitsWindow" 1. 2. 3. 4}"</ |
"==> {"Set traitsWindow" 1. 2. 3. 4}"</syntaxhighlight> |
||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
< |
<syntaxhighlight lang="smalltalk">"Example of creating a collection" |
||
|a| |
|a| |
||
a := #( 1 1 2 'hello' 'world' #symbol #another 2 'hello' #symbol ). |
a := #( 1 1 2 'hello' 'world' #symbol #another 2 'hello' #symbol ). |
||
a asSet.</ |
a asSet.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Set (1 2 #symbol 'world' #another 'hello' )</pre> |
<pre>Set (1 2 #symbol 'world' #another 'hello' )</pre> |
||
Line 3,357: | Line 4,955: | ||
on my system. This can be avoided by using an ordered set (which has also O(n) complexity) as below: |
on my system. This can be avoided by using an ordered set (which has also O(n) complexity) as below: |
||
{{works with|Smalltalk/X}} |
{{works with|Smalltalk/X}} |
||
< |
<syntaxhighlight lang="smalltalk">|a| |
||
a := #( 1 1 2 'hello' 'world' #symbol #another 2 'hello' #symbol ). |
a := #( 1 1 2 'hello' 'world' #symbol #another 2 'hello' #symbol ). |
||
a asOrderedSet.</ |
a asOrderedSet.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>OrderedSet(1 2 'hello' 'world' #symbol #another)</pre> |
<pre>OrderedSet(1 2 'hello' 'world' #symbol #another)</pre> |
||
=={{header|Sparkling}}== |
=={{header|Sparkling}}== |
||
< |
<syntaxhighlight lang="sparkling">function undupe(arr) { |
||
var t = {}; |
var t = {}; |
||
foreach(arr, function(key, val) { |
foreach(arr, function(key, val) { |
||
Line 3,376: | Line 4,974: | ||
return r; |
return r; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|SQL}}== |
|||
{{works with|ORACLE 19c}} |
|||
This is not a particularly efficient solution, but it gets the job done. |
|||
<syntaxhighlight lang="sql"> |
|||
/* |
|||
This code is an implementation of "Remove duplicate elements" in SQL ORACLE 19c |
|||
p_in_str -- input string |
|||
p_delimiter -- delimeter |
|||
*/ |
|||
with |
|||
function remove_duplicate_elements(p_in_str in varchar2, p_delimiter in varchar2 default ',') return varchar2 is |
|||
v_in_str varchar2(32767) := replace(p_in_str,p_delimiter,','); |
|||
v_res varchar2(32767); |
|||
begin |
|||
-- |
|||
execute immediate 'select listagg(distinct cv,:p_delimiter) from (select (column_value).getstringval() cv from xmltable(:v_in_str))' |
|||
into v_res using p_delimiter, v_in_str; |
|||
-- |
|||
return v_res; |
|||
-- |
|||
end; |
|||
--Test |
|||
select remove_duplicate_elements('1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"') as res from dual |
|||
union all |
|||
select remove_duplicate_elements('3 9 1 10 3 7 6 5 2 7 4 7 4 2 2 2 2 8 2 10 4 9 2 4 9 3 4 3 4 7',' ') as res from dual |
|||
; |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1,2,3,4,a,b,c,d |
|||
1 10 2 3 4 5 6 7 8 9 |
|||
</pre> |
|||
=={{header|Stata}}== |
=={{header|Stata}}== |
||
Line 3,382: | Line 5,016: | ||
Stata can report duplicate lines, or remove them. See '''[http://www.stata.com/help.cgi?duplicates duplicates]''' in Stata help. |
Stata can report duplicate lines, or remove them. See '''[http://www.stata.com/help.cgi?duplicates duplicates]''' in Stata help. |
||
< |
<syntaxhighlight lang="stata">. clear all |
||
. input x y |
. input x y |
||
1 1 |
1 1 |
||
Line 3,406: | Line 5,040: | ||
3. | 2 1 | |
3. | 2 1 | |
||
4. | 2 2 | |
4. | 2 2 | |
||
+-------+</ |
+-------+</syntaxhighlight> |
||
===Mata=== |
===Mata=== |
||
Line 3,412: | Line 5,046: | ||
The '''[http://www.stata.com/help.cgi?mf_uniqrows uniqrows]''' function removes duplicate rows from a matrix. |
The '''[http://www.stata.com/help.cgi?mf_uniqrows uniqrows]''' function removes duplicate rows from a matrix. |
||
< |
<syntaxhighlight lang="stata">. mata |
||
: a=1,1\1,1\1,2\2,1\2,2\1,1\2,1\2,1\1,2\2,2 |
: a=1,1\1,1\1,2\2,1\2,2\1,1\2,1\2,1\1,2\2,2 |
||
Line 3,437: | Line 5,071: | ||
3 | 2 1 | |
3 | 2 1 | |
||
4 | 2 2 | |
4 | 2 2 | |
||
+---------+</ |
+---------+</syntaxhighlight> |
||
=={{header|Swift}}== |
=={{header|Swift}}== |
||
Requires elements to be hashable: |
Requires elements to be hashable: |
||
{{works with|Swift|1.2+}} |
{{works with|Swift|1.2+}} |
||
< |
<syntaxhighlight lang="swift">println(Array(Set([3,2,1,2,3,4])))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[2, 3, 1, 4]</pre> |
<pre>[2, 3, 1, 4]</pre> |
||
Line 3,448: | Line 5,082: | ||
Another solution (preserves order of first occurrence). Also requires elements to be hashable: |
Another solution (preserves order of first occurrence). Also requires elements to be hashable: |
||
{{works with|Swift|1.2+}} |
{{works with|Swift|1.2+}} |
||
< |
<syntaxhighlight lang="swift">func uniq<T: Hashable>(lst: [T]) -> [T] { |
||
var seen = Set<T>(minimumCapacity: lst.count) |
var seen = Set<T>(minimumCapacity: lst.count) |
||
return lst.filter { x in |
return lst.filter { x in |
||
Line 3,457: | Line 5,091: | ||
} |
} |
||
println(uniq([3,2,1,2,3,4]))</ |
println(uniq([3,2,1,2,3,4]))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[3, 2, 1, 4]</pre> |
<pre>[3, 2, 1, 4]</pre> |
||
Only requires elements to be equatable, but runs in O(n^2): |
Only requires elements to be equatable, but runs in O(n^2): |
||
< |
<syntaxhighlight lang="swift">func uniq<T: Equatable>(lst: [T]) -> [T] { |
||
var seen = [T]() |
var seen = [T]() |
||
return lst.filter { x in |
return lst.filter { x in |
||
Line 3,473: | Line 5,107: | ||
} |
} |
||
println(uniq([3,2,1,2,3,4]))</ |
println(uniq([3,2,1,2,3,4]))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[3, 2, 1, 4]</pre> |
<pre>[3, 2, 1, 4]</pre> |
||
Line 3,481: | Line 5,115: | ||
What is called "array" in many other languages is probably better represented by the "list" in Tcl (as in LISP). |
What is called "array" in many other languages is probably better represented by the "list" in Tcl (as in LISP). |
||
With the correct option, the <code>lsort</code> command will remove duplicates. |
With the correct option, the <code>lsort</code> command will remove duplicates. |
||
< |
<syntaxhighlight lang="tcl">set result [lsort -unique $listname]</syntaxhighlight> |
||
=={{header|TSE SAL}}== |
|||
<syntaxhighlight lang="tsesal"> |
|||
=={{header|True BASIC}}== |
|||
// |
|||
{{trans|GW-BASIC}} |
|||
// Go through the list, and for each element, check the rest of the list to see if it appears again, and discard it if it does. |
|||
{{works with|QBasic}} |
|||
// |
|||
<lang basic> |
|||
INTEGER PROC FNBlockGetUniqueAllToBufferB( INTEGER bufferI ) |
|||
OPTION BASE 1 |
|||
INTEGER B = FALSE |
|||
LET max = 10 |
|||
INTEGER downB = TRUE |
|||
DIM dat(10), res(10) |
|||
STRING s[255] = "" |
|||
FOR i = 1 TO max |
|||
IF ( NOT ( IsBlockInCurrFile() ) ) Warn( "Please mark a block" ) B = FALSE RETURN( B ) ENDIF // return from the current procedure if no block is marked |
|||
READ dat(i) |
|||
PushPosition() |
|||
NEXT i |
|||
PushBlock() |
|||
GotoBlockBegin() |
|||
DATA 1, 2, 1, 4, 5, 2, 15, 1, 3, 4 |
|||
WHILE ( ( IsCursorInBlock() ) AND ( downB ) ) |
|||
s = GetText( 1, MAXSTRINGLEN ) |
|||
LET res(1) = dat(1) |
|||
PushPosition() |
|||
LET count = 1 |
|||
PushBlock() |
|||
LET posic = 1 |
|||
GotoBufferId( bufferI ) |
|||
DO WHILE posic < max |
|||
IF NOT LFind( s, "" ) |
|||
AddLine( s ) |
|||
ENDIF |
|||
LET indice = 1 |
|||
PopBlock() |
|||
DO WHILE (indice <= count) AND esnuevo = 1 |
|||
PopPosition() |
|||
IF dat(posic) = res(indice) THEN LET esnuevo = 0 |
|||
downB = Down() |
|||
LET indice = indice + 1 |
|||
ENDWHILE |
|||
LOOP |
|||
PopPosition() |
|||
IF esnuevo = 1 THEN |
|||
PopBlock() |
|||
LET count = count + 1 |
|||
B = TRUE |
|||
LET res(count) = dat(posic) |
|||
RETURN( B ) |
|||
END IF |
|||
END |
|||
LOOP |
|||
// |
|||
PROC Main() |
|||
FOR i = 1 TO count |
|||
INTEGER bufferI = 0 |
|||
PRINT res(i); |
|||
PushPosition() |
|||
NEXT i |
|||
bufferI = CreateTempBuffer() |
|||
PopPosition() |
|||
Message( FNBlockGetUniqueAllToBufferB( bufferI ) ) // gives e.g. TRUE |
|||
GotoBufferId( bufferI ) |
|||
END |
END |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} <pre> |
|||
Input |
|||
This is a test1 |
|||
This is a test2 |
|||
This is a test2 |
|||
This is a test2 |
|||
This is a test2 |
|||
This is a test2 |
|||
This is a test3 |
|||
This is a test3 |
|||
This is a test3 |
|||
This is a test3 |
|||
This is a test3 |
|||
This is a test4 |
|||
Output |
|||
This is a test1 |
|||
This is a test2 |
|||
This is a test3 |
|||
This is a test4 |
|||
</pre> |
|||
=={{header|TUSCRIPT}}== |
=={{header|TUSCRIPT}}== |
||
< |
<syntaxhighlight lang="tuscript"> |
||
$$ MODE TUSCRIPT |
$$ MODE TUSCRIPT |
||
list_old="b'A'A'5'1'2'3'2'3'4" |
list_old="b'A'A'5'1'2'3'2'3'4" |
||
Line 3,529: | Line 5,187: | ||
PRINT list_old |
PRINT list_old |
||
PRINT list_new |
PRINT list_new |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} (sorted) |
{{out}} (sorted) |
||
<pre> |
<pre> |
||
Line 3,535: | Line 5,193: | ||
1'2'3'4'5'A'b |
1'2'3'4'5'A'b |
||
</pre> |
</pre> |
||
or |
or |
||
< |
<syntaxhighlight lang="tuscript"> |
||
$$ MODE TUSCRIPT |
$$ MODE TUSCRIPT |
||
list_old="b'A'A'5'1'2'3'2'3'4" |
list_old="b'A'A'5'1'2'3'2'3'4" |
||
Line 3,548: | Line 5,206: | ||
PRINT list_old |
PRINT list_old |
||
PRINT list_new |
PRINT list_new |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 3,557: | Line 5,215: | ||
=={{header|UnixPipes}}== |
=={{header|UnixPipes}}== |
||
Assuming a sequence is represented by lines in a file. |
Assuming a sequence is represented by lines in a file. |
||
< |
<syntaxhighlight lang="bash">bash$ # original list |
||
bash$ printf '6\n2\n3\n6\n4\n2\n' |
bash$ printf '6\n2\n3\n6\n4\n2\n' |
||
6 |
6 |
||
Line 3,571: | Line 5,229: | ||
4 |
4 |
||
6 |
6 |
||
bash$</ |
bash$</syntaxhighlight> |
||
or |
or |
||
< |
<syntaxhighlight lang="bash">bash$ # made uniq |
||
bash$ printf '6\n2\n3\n6\n4\n2\n'|sort -nu |
bash$ printf '6\n2\n3\n6\n4\n2\n'|sort -nu |
||
2 |
2 |
||
Line 3,581: | Line 5,239: | ||
4 |
4 |
||
6 |
6 |
||
bash$</ |
bash$</syntaxhighlight> |
||
=={{header|Ursala}}== |
=={{header|Ursala}}== |
||
Line 3,591: | Line 5,249: | ||
to decide whether that's a relevant criterion for equivalence or else |
to decide whether that's a relevant criterion for equivalence or else |
||
specify a better one. |
specify a better one. |
||
< |
<syntaxhighlight lang="ursala">#cast %s |
||
example = |=hS& 'mississippi'</ |
example = |=hS& 'mississippi'</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>'mspi'</pre> |
<pre>'mspi'</pre> |
||
=={{header|VBA}}== |
|||
Hash Table Approach |
|||
Input list (variant : Long, Double, Boolean and Strings) : |
|||
Array(1.23456789101112E+16, True, False, True, "Alpha", 1, 235, 4, 1.25, 1.25, "Beta", 1.23456789101112E+16, "Delta", "Alpha", "Charlie", 1, 2, "Foxtrot", "Foxtrot", "Alpha", 235) |
|||
<lang vb> |
|||
Option Explicit |
|||
Sub Main() |
|||
Dim myArr() As Variant, i As Long |
|||
myArr = Remove_Duplicate(Array(1.23456789101112E+16, True, False, True, "Alpha", 1, 235, 4, 1.25, 1.25, "Beta", 1.23456789101112E+16, "Delta", "Alpha", "Charlie", 1, 2, "Foxtrot", "Foxtrot", "Alpha", 235)) |
|||
'return : |
|||
For i = LBound(myArr) To UBound(myArr) |
|||
Debug.Print myArr(i) |
|||
Next |
|||
End Sub |
|||
Private Function Remove_Duplicate(Arr As Variant) As Variant() |
|||
Dim myColl As New Collection, Temp() As Variant, i As Long, cpt As Long |
|||
ReDim Temp(UBound(Arr)) |
|||
For i = LBound(Arr) To UBound(Arr) |
|||
On Error Resume Next |
|||
myColl.Add CStr(Arr(i)), CStr(Arr(i)) |
|||
If Err.Number > 0 Then |
|||
On Error GoTo 0 |
|||
Else |
|||
Temp(cpt) = Arr(i) |
|||
cpt = cpt + 1 |
|||
End If |
|||
Next i |
|||
ReDim Preserve Temp(cpt - 1) |
|||
Remove_Duplicate = Temp |
|||
End Function</lang> |
|||
{{out}} |
|||
<pre> 1.23456789101112E+16 |
|||
True |
|||
False |
|||
Alpha |
|||
1 |
|||
235 |
|||
4 |
|||
1.25 |
|||
Beta |
|||
Delta |
|||
Charlie |
|||
2 |
|||
Foxtrot</pre> |
|||
=={{header|VBScript}}== |
|||
Hash Table Approach |
|||
<lang vb> |
|||
Function remove_duplicates(list) |
|||
arr = Split(list,",") |
|||
Set dict = CreateObject("Scripting.Dictionary") |
|||
For i = 0 To UBound(arr) |
|||
If dict.Exists(arr(i)) = False Then |
|||
dict.Add arr(i),"" |
|||
End If |
|||
Next |
|||
For Each key In dict.Keys |
|||
tmp = tmp & key & "," |
|||
Next |
|||
remove_duplicates = Left(tmp,Len(tmp)-1) |
|||
End Function |
|||
WScript.Echo remove_duplicates("a,a,b,b,c,d,e,d,f,f,f,g,h") |
|||
</lang> |
|||
{{Out}} |
|||
<pre>a,b,c,d,e,f,g,h</pre> |
|||
=={{header|Vedit macro language}}== |
=={{header|Vedit macro language}}== |
||
The input "array" is an edit buffer where each line is one element. |
The input "array" is an edit buffer where each line is one element. |
||
< |
<syntaxhighlight lang="vedit">Sort(0, File_Size) // sort the data |
||
While(Replace("^(.*)\N\1$", "\1", REGEXP+BEGIN+NOERR)){} // remove duplicates</ |
While(Replace("^(.*)\N\1$", "\1", REGEXP+BEGIN+NOERR)){} // remove duplicates</syntaxhighlight> |
||
=={{header|Vim Script}}== |
=={{header|Vim Script}}== |
||
<syntaxhighlight lang="vim">call filter(list, 'count(list, v:val) == 1')</syntaxhighlight> |
|||
<lang vim>call filter(list, 'count(list, v:val) == 1')</lang> |
|||
=={{header|Visual FoxPro}}== |
=={{header|Visual FoxPro}}== |
||
< |
<syntaxhighlight lang="vfp"> |
||
LOCAL i As Integer, n As Integer, lcOut As String |
LOCAL i As Integer, n As Integer, lcOut As String |
||
CLOSE DATABASES ALL |
CLOSE DATABASES ALL |
||
Line 3,705: | Line 5,289: | ||
RETURN INT((tnHigh - tnLow + 1)*RAND() + tnLow) |
RETURN INT((tnHigh - tnLow + 1)*RAND() + tnLow) |
||
ENDFUNC |
ENDFUNC |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 3,720: | Line 5,304: | ||
Unique Values: 1,2,3,4,5,6,7,8,9 |
Unique Values: 1,2,3,4,5,6,7,8,9 |
||
</pre> |
|||
=={{header|V (Vlang)}}== |
|||
<syntaxhighlight lang="v (vlang)">const list = 'a,1,a,b,b,c,d,e,d,0,f,f,5,f,g,h,1,3,3' |
|||
fn main() { |
|||
println(unique(list)) |
|||
} |
|||
fn unique(list string) []string { |
|||
mut new_list := []string{} |
|||
for word in list.split(',') { |
|||
if new_list.any(it == word.str()) == false { |
|||
new_list << word |
|||
} |
|||
} |
|||
new_list.sort() |
|||
return new_list |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
['0', '1', '3', '5', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] |
|||
</pre> |
</pre> |
||
=={{header|Wart}}== |
=={{header|Wart}}== |
||
< |
<syntaxhighlight lang="python">def (dedup l) |
||
let exists (table) |
let exists (table) |
||
collect+each x l |
collect+each x l |
||
unless exists.x |
unless exists.x |
||
yield x |
yield x |
||
exists.x <- 1</ |
exists.x <- 1</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,735: | Line 5,342: | ||
=={{header|Wortel}}== |
=={{header|Wortel}}== |
||
< |
<syntaxhighlight lang="wortel">@uniq [1 2 3 2 1 2 3] ; returns [1 2 3]</syntaxhighlight> |
||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
{{libheader|Wren-sort}} |
{{libheader|Wren-sort}} |
||
< |
<syntaxhighlight lang="wren">import "./sort" for Sort |
||
// Using a map - order of distinct items is undefined. |
// Using a map - order of distinct items is undefined. |
||
Line 3,782: | Line 5,389: | ||
System.print("Method 1: %(removeDuplicates1.call(a.toList))") // copy original each time |
System.print("Method 1: %(removeDuplicates1.call(a.toList))") // copy original each time |
||
System.print("Method 2: %(removeDuplicates2.call(a.toList))") |
System.print("Method 2: %(removeDuplicates2.call(a.toList))") |
||
System.print("Method 3: %(removeDuplicates3.call(a.toList))")</ |
System.print("Method 3: %(removeDuplicates3.call(a.toList))")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,792: | Line 5,399: | ||
</pre> |
</pre> |
||
=={{header|XBS}}== |
|||
<syntaxhighlight lang="xbs">func RemoveDuplicates(Array){ |
|||
set NewArray = []; |
|||
foreach(k,v as Array){ |
|||
if (NewArray->includes(v)){ |
|||
Array->splice(toint(k),1); |
|||
} else { |
|||
NewArray->push(v); |
|||
} |
|||
} |
|||
} |
|||
set Arr = ["Hello",1,2,"Hello",3,1]; |
|||
log(Arr); |
|||
RemoveDuplicates(Arr); |
|||
log(Arr);</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Hello,1,2,Hello,3,1 |
|||
Hello,1,2,3 |
|||
</pre> |
|||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">code Text=12; \built-in routine to display a string of characters |
||
string 0; \use zero-terminated strings (not MSb terminated) |
string 0; \use zero-terminated strings (not MSb terminated) |
||
Line 3,818: | Line 5,445: | ||
]; |
]; |
||
Text(0, Unique("Pack my box with five dozen liquor jugs."))</ |
Text(0, Unique("Pack my box with five dozen liquor jugs."))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,824: | Line 5,451: | ||
Pack myboxwithfvedznlqurjgs. |
Pack myboxwithfvedznlqurjgs. |
||
</pre> |
</pre> |
||
=={{header|Yabasic}}== |
|||
<lang Yabasic>data "Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "to", "the", "aid", "of", "the", "party.", "" |
|||
do |
|||
read p$ |
|||
if p$ = "" break |
|||
if not instr(r$, p$) r$ = r$ + p$ + " " |
|||
loop |
|||
print r$</lang> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
Using built ins: |
Using built ins: |
||
< |
<syntaxhighlight lang="zkl">zkl: Utils.Helpers.listUnique(T(1,3,2,9,1,2,3,8,8,"8",1,0,2,"8")) |
||
L(1,3,2,9,8,"8",0) |
L(1,3,2,9,8,"8",0) |
||
zkl: "1,3,2,9,1,2,3,8,8,1,0,2".unique() |
zkl: "1,3,2,9,1,2,3,8,8,1,0,2".unique() |
||
,012389</ |
,012389</syntaxhighlight> |
||
Where listUnique is brute force: |
Where listUnique is brute force: |
||
< |
<syntaxhighlight lang="zkl">fcn listUnique(xs){ |
||
xs.reduce(fcn(us,s){us.holds(s) and us or us.append(s)},L()) }</ |
xs.reduce(fcn(us,s){us.holds(s) and us or us.append(s)},L()) }</syntaxhighlight> |
||
=={{header|Zoea}}== |
=={{header|Zoea}}== |
||
<syntaxhighlight lang="zoea"> |
|||
<lang Zoea> |
|||
program: remove_duplicate_elements |
program: remove_duplicate_elements |
||
input: [1,2,1,3,2,4,1] |
input: [1,2,1,3,2,4,1] |
||
output: [1,2,3,4] |
output: [1,2,3,4] |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Zoea Visual}}== |
=={{header|Zoea Visual}}== |
Latest revision as of 19:13, 16 June 2024
You are encouraged to solve this task according to the task description, using any language you may know.
Sorting Algorithm
This is a sorting algorithm. It may be applied to a set of data in order to sort it.
For comparing various sorts, see compare sorts.
For other sorting algorithms, see sorting algorithms, or:
Heap sort | Merge sort | Patience sort | Quick sort
O(n log2n) sorts
Shell Sort
O(n2) sorts
Bubble sort |
Cocktail sort |
Cocktail sort with shifting bounds |
Comb sort |
Cycle sort |
Gnome sort |
Insertion sort |
Selection sort |
Strand sort
other sorts
Bead sort |
Bogo sort |
Common sorted list |
Composite structures sort |
Custom comparator sort |
Counting sort |
Disjoint sublist sort |
External sort |
Jort sort |
Lexicographical sort |
Natural sorting |
Order by pair comparisons |
Order disjoint list items |
Order two numerical lists |
Object identifier (OID) sort |
Pancake sort |
Quickselect |
Permutation sort |
Radix sort |
Ranking methods |
Remove duplicate elements |
Sleep sort |
Stooge sort |
[Sort letters of a string] |
Three variable sort |
Topological sort |
Tree sort
Given an Array, derive a sequence of elements in which all duplicates are removed.
There are basically three approaches seen here:
- Put the elements into a hash table which does not allow duplicates. The complexity is O(n) on average, and O(n2) worst case. This approach requires a hash function for your type (which is compatible with equality), either built-in to your language, or provided by the user.
- Sort the elements and remove consecutive duplicate elements. The complexity of the best sorting algorithms is O(n log n). This approach requires that your type be "comparable", i.e., have an ordering. Putting the elements into a self-balancing binary search tree is a special case of sorting.
- Go through the list, and for each element, check the rest of the list to see if it appears again, and discard it if it does. The complexity is O(n2). The up-shot is that this always works on any type (provided that you can test for equality).
11l
V items = [‘1’, ‘2’, ‘3’, ‘a’, ‘b’, ‘c’, ‘2’, ‘3’, ‘4’, ‘b’, ‘c’, ‘d’]
V unique = Array(Set(items))
print(unique)
- Output:
[1, 2, 3, 4, a, b, c, d]
360 Assembly
* Remove duplicate elements - 18/10/2015
REMDUP CSECT
USING REMDUP,R15 set base register
SR R6,R6 i=0
LA R8,1 k=1
LOOPK C R8,N do k=1 to n
BH ELOOPK
LR R1,R8 k
SLA R1,2
L R9,T-4(R1) e=t(k)
LR R7,R8 k
BCTR R7,0 j=k-1
LOOPJ C R7,=F'1' do j=k-1 to 1 by -1
BL ELOOPJ
LR R1,R7 j
SLA R1,2
L R2,T-4(R1) t(j)
CR R9,R2 if e=t(j) then goto iter
BE ITER
BCTR R7,0 j=j-1
B LOOPJ
ELOOPJ LA R6,1(R6) i=i+1
LR R1,R6 i
SLA R1,2
ST R9,T-4(R1) t(i)=e
ITER LA R8,1(R8) k=k+1
B LOOPK
ELOOPK LA R10,PG pgi=@pg
LA R8,1 k=1
LOOP CR R8,R6 do k=1 to i
BH ELOOP
LR R1,R8 k
SLA R1,2
L R2,T-4(R1) t(k)
XDECO R2,PG+80 edit t(k)
MVC 0(3,R10),PG+89 output t(k) on 3 char
LA R10,3(R10) pgi=pgi+3
LA R8,1(R8) k=k+1
B LOOP
ELOOP XPRNT PG,80 print buffer
XR R15,R15 set return code
BR R14 return to caller
T DC F'6',F'6',F'1',F'5',F'6',F'2',F'1',F'7',F'5',F'22'
DC F'4',F'19',F'1',F'1',F'6',F'8',F'9',F'10',F'11',F'12'
N DC A((N-T)/4) number of T items
PG DC CL92' '
YREGS
END REMDUP
- Output:
6 1 5 2 7 22 4 19 8 9 10 11 12
8080 Assembly
This routine works on arrays of bytes, and keeps track of which bytes it has seen in a 256-byte array.
org 100h
jmp test
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Given an array of bytes starting at HL with length BC,
;; remove all duplicates in the array. The new end of the array
;; is returned in HL. A page of memory (256 bytes) is required
;; to mark which bytes have been seen.
uniqpage: equ 3 ; Page to use - a compile-time constant.
; This would need to be set to a page that
; the rest of the program doesn't need.
uniq: xra a ; Zero out the page
lxi d,uniqpage * 256
uniqzero: stax d ; Zero out a byte
inr e ; And do the next byte
jnz uniqzero
mov d,h ; Keep a second pointer to the array in DE
mov e,l
uniqpos: ldax d ; Read from high pointer
mov m,a ; Write to low pointer
inx d ; Increment the high pointer
push h ; Keep low pointer around
mvi h,uniqpage
mov l,a ; Have we seen this byte yet?
cmp m
mov m,a ; No matter what, we've certainly seen it now
pop h ; Bring back the low pointer
jz uniqno ; If we already had it, don't increment low ptr
inx h ; IF we didn't, do increment it
uniqno: dcx b ; One fewer byte left
mov a,b ; If there are zero bytes left,
ora c
rz ; Then return to caller
jmp uniqpos ; Otherwise, do the next byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Testing code: read a string from the CP/M console, run
;; uniq, then print the output.
test: lxi d,bufdef ; Read a string
mvi c,10
call 5
lxi d,nl ; Output on new line
mvi c,9
call 5
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lda bufdef+1 ; Length of input string
mov c,a ; Extend to 16-bit (since uniq supports
mvi b,0 ; long arrays)
lxi h,buf ; Location of input string
call uniq ; Only the unique bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mvi m,'$' ; Mark the (string) end with '$'
lxi d,buf ; Print the string, which now has had
mvi c,9 ; all duplicates removed.
jmp 5
nl: db 13,10,'$'
bufdef: db 127,0
buf:
ACL2
(remove-duplicates xs)
Action!
INCLUDE "D2:SORT.ACT" ;from the Action! Tool Kit
PROC PrintArray(INT ARRAY a INT size)
INT i
Put('[)
FOR i=0 TO size-1
DO
IF i>0 THEN Put(' ) FI
PrintI(a(i))
OD
Put(']) PutE()
RETURN
PROC RemoveDuplicates(INT ARRAY src INT srcLen
INT ARRAY dst INT POINTER dstLen)
INT i
CHAR curr,prev
IF srcLen=0 THEN
dstLen^=0
RETURN
FI
SortI(src,srcLen,0)
dst(0)=src(0)
dstLen^=1 prev=src(0)
FOR i=1 TO srcLen-1
DO
curr=src(i)
IF curr#prev THEN
dst(dstLen^)=curr
dstLen^==+1
FI
prev=curr
OD
RETURN
PROC Test(INT ARRAY src INT srcLen)
INT ARRAY dst(100)
INT dstLen
PrintE("Input array:")
PrintArray(src,srcLen)
RemoveDuplicates(src,srcLen,dst,@dstLen)
PrintE("Unique items:")
PrintArray(dst,dstLen)
PutE()
RETURN
PROC Main()
INT ARRAY src1(9)=[1 3 65534 0 12 1 65534 52 3]
INT ARRAY src2(26)=[3 2 1 3 2 5 2 1 6 3 4 2 5 3 1 5 3 5 2 1 3 7 4 5 7 6]
INT ARRAY src3(1)=[6502]
Put(125) PutE() ;clear screen
Test(src1,9)
Test(src2,26)
Test(src3,1)
RETURN
- Output:
Screenshot from Atari 8-bit computer
Input array: [1 3 -2 0 12 1 -2 52 3] Unique items: [-2 0 1 3 12 52] Input array: [3 2 1 3 2 5 2 1 6 3 4 2 5 3 1 5 3 5 2 1 3 7 4 5 7 6] Unique items: [1 2 3 4 5 6 7] Input array: [6502] Unique items: [6502]
Ada
with Ada.Containers.Ordered_Sets, Ada.Text_IO;
use Ada.Text_IO;
procedure Duplicate is
package Int_Sets is new Ada.Containers.Ordered_Sets (Integer);
Nums : constant array (Natural range <>) of Integer := (1,2,3,4,5,5,6,7,1);
Unique : Int_Sets.Set;
begin
for n of Nums loop
Unique.Include (n);
end loop;
for e of Unique loop
Put (e'img);
end loop;
end Duplicate;
Aime
Using an index:
index x;
list(1, 2, 3, 1, 2, 3, 4, 1).ucall(i_add, 1, x, 0);
x.i_vcall(o_, 1, " ");
o_newline();
- Output:
1 2 3 4
Order preserving solution:
index x;
for (, integer a in list(8, 2, 1, 8, 2, 1, 4, 8)) {
if ((x[a] += 1) == 1) {
o_(" ", a);
}
}
o_newline();
- Output:
8 2 1 4
ALGOL 68
Using the associative array code from Associative_array/Iteration#ALGOL_68
# use the associative array in the Associate array/iteration task #
# this example uses strings - for other types, the associative #
# array modes AAELEMENT and AAKEY should be modified as required #
PR read "aArray.a68" PR
# returns the unique elements of list #
PROC remove duplicates = ( []STRING list )[]STRING:
BEGIN
REF AARRAY elements := INIT LOC AARRAY;
INT count := 0;
FOR pos FROM LWB list TO UPB list DO
IF NOT ( elements CONTAINSKEY list[ pos ] ) THEN
# first occurance of this element #
elements // list[ pos ] := "";
count +:= 1
FI
OD;
# construct an array of the unique elements from the #
# associative array - the new list will not necessarily be #
# in the original order #
[ count ]STRING result;
REF AAELEMENT e := FIRST elements;
FOR pos WHILE e ISNT nil element DO
result[ pos ] := key OF e;
e := NEXT elements
OD;
result
END; # remove duplicates #
# test the duplicate removal #
print( ( remove duplicates( ( "A", "B", "D", "A", "C", "F", "F", "A" ) ), newline ) )
Amazing Hopper
#include <hopper.h>
main:
x=-1
{30} rand array (x), mulby(10), ceil, mov(x)
{"Original Array:\n",x}, println
{x}array(SORT),
{x}sets(UNIQUE), mov(x)
{"Final array:\n",x}, println
y={}
{"C","Go","Go","C","Cobol","java","Ada"} pushall(y)
{"java","algol-68","C","java","fortran"} pushall(y)
{"\nOriginal Array:\n",y}, println
{y}array(SORT),
{y}sets(UNIQUE), mov(y)
{"Final array:\n",y}, println
exit(0)
- Output:
Original Array: 3 9 1 10 3 7 6 5 2 7 4 7 4 2 2 2 2 8 2 10 4 9 2 4 9 3 4 3 4 7 Final array: 1 2 3 4 5 6 7 8 9 10 Original Array: C Go Go C Cobol java Ada java algol-68 C java fortran Final array: Ada C Cobol Go algol-68 fortran java
APL
The primitive monad ∪ means "unique", so:
∪ 1 2 3 1 2 3 4 1
1 2 3 4
w←1 2 3 1 2 3 4 1
((⍳⍨w)=⍳⍴w)/w
1 2 3 4
AppleScript
Idiomatic
unique({1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"})
on unique(x)
set R to {}
repeat with i in x
if i is not in R then set end of R to i's contents
end repeat
return R
end unique
Idiomatic 2 (more robust)
While it's quite common to see 'is in', 'is not in', 'contains', and 'does not contain' used in the above way for convenience when the scripter knows the code will only be used to check for simple objects, the commands actually compare sections of list rather than individual elements.
{1, 2, 3, {4, 5}} contains {2, 3} --> true
{1, 2, 3, {4, 5}} contains {4, 5} --> false
{1, 2, 3, {4, 5}} contains {{4, 5}} --> true
If the search term presented is anything other than a list, it's silently coerced to one for the search.
3 is in {1, 2, 3, {4, 5}} --> {3} is in {1, 2, 3, {4, 5}} --> true
So for robustness in case the elements sought may already be lists, or records, it's best to wrap them explicitly in list braces.
unique({1, 2, 3, "a", "b", "c", 2, 3, 4, "c", {b:"c"}, {"c"}, "c", "d"})
on unique(x)
set R to {}
repeat with i in x
set i to i's contents
if {i} is not in R then set end of R to i
end repeat
return R
end unique
- Output:
{1, 2, 3, "a", "b", "c", 4, {b:"c"}, {"c"}, "d"}
Functional
Or, more generally, we can allow for customised definitions of equality and duplication, by following the Haskell prelude in defining a nub :: [a] -> [a] function which is a special case of nubBy :: (a -> a -> Bool) -> [a] -> [a]
In the following example, equality is defined as case-insensitive for strings. We would obtain a different list of unique strings by adjusting the Eq :: a -> a -> Bool function to make it consider case.
-- CASE-INSENSITIVE UNIQUE ELEMENTS ------------------------------------------
-- nub :: [a] -> [a]
on nub(xs)
-- Eq :: a -> a -> Bool
script Eq
on |λ|(x, y)
ignoring case
x = y
end ignoring
end |λ|
end script
nubBy(Eq, xs)
end nub
-- TEST ----------------------------------------------------------------------
on run
{intercalate(space, ¬
nub(splitOn(space, "4 3 2 8 0 1 9 5 1 7 6 3 9 9 4 2 1 5 3 2"))), ¬
intercalate("", ¬
nub(characters of "abcabc ABCABC"))}
--> {"4 3 2 8 0 1 9 5 7 6", "abc "}
end run
-- GENERIC FUNCTIONS ---------------------------------------------------------
-- filter :: (a -> Bool) -> [a] -> [a]
on filter(f, xs)
tell mReturn(f)
set lst to {}
set lng to length of xs
repeat with i from 1 to lng
set v to item i of xs
if |λ|(v, i, xs) then set end of lst to v
end repeat
return lst
end tell
end filter
-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
set {dlm, my text item delimiters} to {my text item delimiters, strText}
set strJoined to lstText as text
set my text item delimiters to dlm
return strJoined
end intercalate
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- nubBy :: (a -> a -> Bool) -> [a] -> [a]
on nubBy(fnEq, xxs)
set lng to length of xxs
if lng > 1 then
set x to item 1 of xxs
set xs to items 2 thru -1 of xxs
set p to mReturn(fnEq)
-- notEq :: a -> Bool
script notEq
on |λ|(a)
not (p's |λ|(a, x))
end |λ|
end script
{x} & nubBy(fnEq, filter(notEq, xs))
else
xxs
end if
end nubBy
-- splitOn :: Text -> Text -> [Text]
on splitOn(strDelim, strMain)
set {dlm, my text item delimiters} to {my text item delimiters, strDelim}
set lstParts to text items of strMain
set my text item delimiters to dlm
return lstParts
end splitOn
- Output:
{"4 3 2 8 0 1 9 5 7 6", "abc "}
AppleScriptObjC
use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
set aList to {1, 2, 3, "a", "b", "c", 2, 3, 4, "c", {b:"c"}, {"c"}, "c", "d"}
set orderedSet to current application's class "NSOrderedSet"'s orderedSetWithArray:(aList)
return orderedSet's array() as list
- Output:
{1, 2, 3, "a", "b", "c", 4, {b:"c"}, {"c"}, "d"}
Arturo
arr: [1 2 3 2 1 2 3 4 5 3 2 1]
print unique arr
- Output:
1 2 3 4 5
ATS
ATS2 implementation for values having an equality predicate
This method runs no worse than O(n*n) in the number of elements. It is an example of the brute-force technique.
The implementation is for non-linear types, only. I implement the predicate as a non-linear closure.
(* Remove duplicate elements.
This implementation is for elements that have an "equals" (or
"equivalence") predicate. It runs O(n*n) in the number of
elements. *)
#include "share/atspre_staload.hats"
(* How the remove_dups template function will be called. *)
extern fn {a : t@ype}
remove_dups
{n : int}
(eq : (a, a) -<cloref> bool,
src : arrayref (a, n),
n : size_t n,
dst : arrayref (a, n),
m : &size_t? >> size_t m)
:<!refwrt> #[m : nat | m <= n]
void
(* An implementation of the remove_dups template function. *)
implement {a}
remove_dups {n} (eq, src, n, dst, m) =
if n = i2sz 0 then
m := i2sz 0
else
let
fun
peruse_src
{i : int | 1 <= i; i <= n}
{j : int | 1 <= j; j <= i}
.<n - i>.
(i : size_t i,
j : size_t j)
:<!refwrt> [m : int | 1 <= m; m <= n]
size_t m =
let
fun
already_seen
{k : int | 0 <= k; k <= j}
.<j - k>.
(x : a,
k : size_t k)
:<!ref> bool =
if k = j then
false
else if eq (x, dst[k]) then
true
else
already_seen (x, succ k)
in
if i = n then
j
else if already_seen (src[i], i2sz 0) then
peruse_src (succ i, j)
else
begin
dst[j] := src[i];
peruse_src (succ i, succ j)
end
end
prval () = lemma_arrayref_param src (* Prove 0 <= n. *)
in
dst[0] := src[0];
m := peruse_src (i2sz 1, i2sz 1)
end
implement (* A demonstration with strings. *)
main0 () =
let
val eq = lam (x : string, y : string) : bool =<cloref> (x = y)
val src =
arrayref_make_list<string>
(10, $list ("a", "c", "b", "e", "a",
"a", "d", "d", "b", "c"))
val dst = arrayref_make_elt<string> (i2sz 10, "?")
var m : size_t
in
remove_dups<string> (eq, src, i2sz 10, dst, m);
let
prval [m : int] EQINT () = eqint_make_guint m
var i : natLte m
in
for (i := 0; i2sz i <> m; i := succ i)
print! (" ", dst[i] : string);
println! ()
end
end
- Output:
a c b e d
ATS2 implementation for linear values having an equality predicate
This method runs no worse than O(n*n) in the number of elements. It is another example of the brute-force technique.
This implementation can handle elements of linear type. I implement the predicate as a template function. There are two interfaces: one for an array, and one for a linked list.
(* Remove duplicate elements.
This implementation is for elements that have an "equals" (or
"equivalence") predicate. It runs O(n*n) in the number of
elements. It uses a linked list and supports linear types.
The equality predicate is implemented as a template function. *)
#include "share/atspre_staload.hats"
staload UN = "prelude/SATS/unsafe.sats"
#define NIL list_vt_nil ()
#define :: list_vt_cons
(*------------------------------------------------------------------*)
(* Interfaces *)
extern fn {a : vt@ype}
array_remove_dups
{n : int}
{p_arr : addr}
(pf_arr : array_v (a, p_arr, n) |
p_arr : ptr p_arr,
n : size_t n)
:<!wrt> [m : nat | m <= n]
@(array_v (a, p_arr, m),
array_v (a?, p_arr + (m * sizeof a), n - m) |
size_t m)
extern fn {a : vt@ype}
list_vt_remove_dups
{n : int}
(lst : list_vt (a, n))
:<!wrt> [m : nat | m <= n]
list_vt (a, m)
extern fn {a : vt@ype}
remove_dups$eq :
(&a, &a) -<> bool
extern fn {a : vt@ype}
remove_dups$clear :
(&a >> a?) -< !wrt > void
(*------------------------------------------------------------------*)
(* Implementation of array_remove_dups *)
(* The implementation for arrays converts to a list_vt, does the
removal duplicates, and then writes the data back into the original
array. *)
implement {a}
array_remove_dups {n} {p_arr} (pf_arr | p_arr, n) =
let
var lst = array_copy_to_list_vt<a> (!p_arr, n)
var m : int
val lst = list_vt_remove_dups<a> lst
val m = list_vt_length lst
prval [m : int] EQINT () = eqint_make_gint m
prval @(pf_uniq, pf_rest) =
array_v_split {a?} {p_arr} {n} {m} pf_arr
val () = array_copy_from_list_vt<a> (!p_arr, lst)
in
@(pf_uniq, pf_rest | i2sz m)
end
(*------------------------------------------------------------------*)
(* Implementation of list_vt_remove_dups *)
(* The list is worked on "in place". That is, no nodes are copied or
moved to new locations, except those that are removed and freed. *)
fn {a : vt@ype}
remove_equal_elements
{n : int}
(x : &a,
lst : &list_vt (a, n) >> list_vt (a, m))
:<!wrt> #[m : nat | m <= n]
void =
let
fun {a : vt@ype}
remove_elements
{n : nat}
.<n>.
(x : &a,
lst : &list_vt (a, n) >> list_vt (a, m))
:<!wrt> #[m : nat | m <= n]
void =
case+ lst of
| NIL => ()
| @ (head :: tail) =>
if remove_dups$eq (head, x) then
let
val new_lst = tail
val () = remove_dups$clear<a> head
val () = free@{a}{0} lst
val () = lst := new_lst
in
remove_elements {n - 1} (x, lst)
end
else
let
val () = remove_elements {n - 1} (x, tail)
prval () = fold@ lst
in
end
prval () = lemma_list_vt_param lst
in
remove_elements {n} (x, lst)
end
fn {a : vt@ype}
remove_dups
{n : int}
(lst : &list_vt (a, n) >> list_vt (a, m))
:<!wrt> #[m : nat | m <= n]
void =
let
fun
rmv_dups {n : nat}
.<n>.
(lst : &list_vt (a, n) >> list_vt (a, m))
:<!wrt> #[m : nat | m <= n]
void =
case+ lst of
| NIL => ()
| head :: NIL => ()
| @ head :: tail =>
let
val () = remove_equal_elements (head, tail)
val () = rmv_dups tail
prval () = fold@ lst
in
end
prval () = lemma_list_vt_param lst
in
rmv_dups {n} lst
end
implement {a}
list_vt_remove_dups {n} lst =
let
var lst = lst
in
remove_dups {n} lst;
lst
end
(*------------------------------------------------------------------*)
implement
remove_dups$eq<Strptr1> (s, t) =
($UN.strptr2string s = $UN.strptr2string t)
implement
remove_dups$clear<Strptr1> s =
strptr_free s
implement
array_uninitize$clear<Strptr1> (i, s) =
strptr_free s
implement
fprint_ref<Strptr1> (outf, s) =
fprint! (outf, $UN.strptr2string s)
implement (* A demonstration with linear strings. *)
main0 () =
let
#define N 10
val data =
$list_vt{Strptr1}
(string0_copy "a", string0_copy "c", string0_copy "b",
string0_copy "e", string0_copy "a", string0_copy "a",
string0_copy "d", string0_copy "d", string0_copy "b",
string0_copy "c")
var arr : @[Strptr1][N]
val () = array_copy_from_list_vt<Strptr1> (arr, data)
prval pf_arr = view@ arr
val p_arr = addr@ arr
val [m : int]
@(pf_uniq, pf_abandoned | m) =
array_remove_dups<Strptr1> (pf_arr | p_arr, i2sz N)
val () = fprint_array_sep<Strptr1> (stdout_ref, !p_arr, m, " ")
val () = println! ()
val () = array_uninitize<Strptr1> (!p_arr, m)
prval () = view@ arr :=
array_v_unsplit (pf_uniq, pf_abandoned)
in
end
(*------------------------------------------------------------------*)
- Output:
a c b e d
ATS2 implementation for values having both order and equality predicates
Sort the elements and then keep only the first element of each run of equal elements.
This method is limited in speed by the speed of the sorting algorithm. That can vary greatly according to algorithm and circumstances, but typically is much better than O(n*n). Below (simply because it is convenient) I use the quicksort that is in the ATS2 prelude.
(* Remove duplicate elements.
The elements are sorted and then only unique values are kept. *)
#include "share/atspre_staload.hats"
(* How the remove_dups template function will be called. *)
extern fn {a : t@ype}
remove_dups
{n : int}
(lt : (a, a) -<cloref> bool, (* "less than" *)
eq : (a, a) -<cloref> bool, (* "equals" *)
src : arrayref (a, n),
n : size_t n,
dst : arrayref (a, n),
m : &size_t? >> size_t m)
: #[m : nat | m <= n]
void
implement {a}
remove_dups {n} (lt, eq, src, n, dst, m) =
if n = i2sz 0 then
m := i2sz 0
else
let
prval () = lemma_arrayref_param src (* Prove 0 <= n. *)
(* Sort a copy of src. *)
val arr = arrayptr_refize (arrayref_copy (src, n))
implement array_quicksort$cmp<a> (x, y) =
if x \lt y then ~1 else 1
val () = arrayref_quicksort<a> (arr, n)
(* Copy only the first element of each run of equal elements. *)
val () = dst[0] := arr[0]
fun
loop {i : int | 1 <= i; i <= n}
{j : int | 1 <= j; j <= i}
.<n - i>.
(i : size_t i,
j : size_t j)
: [m : int | 1 <= m; m <= n]
size_t m =
if i = n then
j
else if arr[pred i] \eq arr[i] then
loop (succ i, j)
else
begin
dst[j] := arr[i];
loop (succ i, succ j)
end
val () = m := loop (i2sz 1, i2sz 1)
in
end
implement (* A demonstration. *)
main0 () =
let
val src =
arrayref_make_list<string>
(10, $list ("a", "c", "b", "e", "a",
"a", "d", "d", "b", "c"))
val dst = arrayref_make_elt<string> (i2sz 10, "?")
var m : size_t
in
remove_dups<string> (lam (x, y) => x < y,
lam (x, y) => x = y,
src, i2sz 10, dst, m);
let
prval [m : int] EQINT () = eqint_make_guint m
var i : natLte m
in
for (i := 0; i2sz i <> m; i := succ i)
print! (" ", dst[i]);
println! ()
end
end
- Output:
a b c d e
ATS2 implementation using a radix sort
This method runs in O(nw) time, where n is the number of elements n and w is a factor that is constant for elements that are fixed-size integers.
The implementation is for unsigned integers and puts the unique numbers into a second array in ascending order.
Radix sorting can sort an array of elements only into the encoding order of their keys, but that is a common case. Here the only reason to sort at all is to quickly eliminate duplicates.
(* Remove duplicate elements.
The best sorting algorithms, it is said, are O(n log n) and require
an order predicate.
But this is true only for a general sorting routine. A radix sort
for fixed-size integers is O(n), and requires no order predicate.
Here I use such a radix sort. *)
#include "share/atspre_staload.hats"
staload UN = "prelude/SATS/unsafe.sats"
(* How the remove_dups template function will be called. *)
extern fn {tk : tkind}
remove_dups
{n : int}
(src : arrayref (g0uint tk, n),
n : size_t n,
dst : arrayref (g0uint tk, n),
m : &size_t? >> size_t m)
: #[m : nat | m <= n]
void
(*------------------------------------------------------------------*)
(* A radix sort for unsigned integers, copied from my contribution to
the radix sort task. *)
extern fn {a : vt@ype}
{tk : tkind}
g0uint_radix_sort
{n : int}
(arr : &array (a, n) >> _,
n : size_t n)
:<!wrt> void
extern fn {a : vt@ype}
{tk : tkind}
g0uint_radix_sort$key
{n : int}
{i : nat | i < n}
(arr : &RD(array (a, n)),
i : size_t i)
:<> g0uint tk
fn {}
bin_sizes_to_indices
(bin_indices : &array (size_t, 256) >> _)
:<!wrt> void =
let
fun
loop {i : int | i <= 256}
{accum : int}
.<256 - i>.
(bin_indices : &array (size_t, 256) >> _,
i : size_t i,
accum : size_t accum)
:<!wrt> void =
if i <> i2sz 256 then
let
prval () = lemma_g1uint_param i
val elem = bin_indices[i]
in
if elem = i2sz 0 then
loop (bin_indices, succ i, accum)
else
begin
bin_indices[i] := accum;
loop (bin_indices, succ i, accum + g1ofg0 elem)
end
end
in
loop (bin_indices, i2sz 0, i2sz 0)
end
fn {a : vt@ype}
{tk : tkind}
count_entries
{n : int}
{shift : nat}
(arr : &RD(array (a, n)),
n : size_t n,
bin_indices : &array (size_t?, 256)
>> array (size_t, 256),
all_expended : &bool? >> bool,
shift : int shift)
:<!wrt> void =
let
fun
loop {i : int | i <= n}
.<n - i>.
(arr : &RD(array (a, n)),
bin_indices : &array (size_t, 256) >> _,
all_expended : &bool >> bool,
i : size_t i)
:<!wrt> void =
if i <> n then
let
prval () = lemma_g1uint_param i
val key : g0uint tk = g0uint_radix_sort$key<a><tk> (arr, i)
val key_shifted = key >> shift
val digit = ($UN.cast{uint} key_shifted) land 255U
val [digit : int] digit = g1ofg0 digit
extern praxi set_range :
() -<prf> [0 <= digit; digit <= 255] void
prval () = set_range ()
val count = bin_indices[digit]
val () = bin_indices[digit] := succ count
in
all_expended := all_expended * iseqz key_shifted;
loop (arr, bin_indices, all_expended, succ i)
end
prval () = lemma_array_param arr
in
array_initize_elt<size_t> (bin_indices, i2sz 256, i2sz 0);
all_expended := true;
loop (arr, bin_indices, all_expended, i2sz 0)
end
fn {a : vt@ype}
{tk : tkind}
sort_by_digit
{n : int}
{shift : nat}
(arr1 : &RD(array (a, n)),
arr2 : &array (a, n) >> _,
n : size_t n,
all_expended : &bool? >> bool,
shift : int shift)
:<!wrt> void =
let
var bin_indices : array (size_t, 256)
in
count_entries<a><tk> (arr1, n, bin_indices, all_expended, shift);
if all_expended then
()
else
let
fun
rearrange {i : int | i <= n}
.<n - i>.
(arr1 : &RD(array (a, n)),
arr2 : &array (a, n) >> _,
bin_indices : &array (size_t, 256) >> _,
i : size_t i)
:<!wrt> void =
if i <> n then
let
prval () = lemma_g1uint_param i
val key = g0uint_radix_sort$key<a><tk> (arr1, i)
val key_shifted = key >> shift
val digit = ($UN.cast{uint} key_shifted) land 255U
val [digit : int] digit = g1ofg0 digit
extern praxi set_range :
() -<prf> [0 <= digit; digit <= 255] void
prval () = set_range ()
val [j : int] j = g1ofg0 bin_indices[digit]
(* One might wish to get rid of this assertion somehow,
to eliminate the branch, should it prove a
problem. *)
val () = $effmask_exn assertloc (j < n)
val p_dst = ptr_add<a> (addr@ arr2, j)
and p_src = ptr_add<a> (addr@ arr1, i)
val _ = $extfcall (ptr, "memcpy", p_dst, p_src,
sizeof<a>)
val () = bin_indices[digit] := succ (g0ofg1 j)
in
rearrange (arr1, arr2, bin_indices, succ i)
end
prval () = lemma_array_param arr1
in
bin_sizes_to_indices<> bin_indices;
rearrange (arr1, arr2, bin_indices, i2sz 0)
end
end
fn {a : vt@ype}
{tk : tkind}
g0uint_sort {n : pos}
(arr1 : &array (a, n) >> _,
arr2 : &array (a, n) >> _,
n : size_t n)
:<!wrt> void =
let
fun
loop {idigit_max, idigit : nat | idigit <= idigit_max}
.<idigit_max - idigit>.
(arr1 : &array (a, n) >> _,
arr2 : &array (a, n) >> _,
from1to2 : bool,
idigit_max : int idigit_max,
idigit : int idigit)
:<!wrt> void =
if idigit = idigit_max then
begin
if ~from1to2 then
let
val _ =
$extfcall (ptr, "memcpy", addr@ arr1, addr@ arr2,
sizeof<a> * n)
in
end
end
else if from1to2 then
let
var all_expended : bool
in
sort_by_digit<a><tk> (arr1, arr2, n, all_expended,
8 * idigit);
if all_expended then
()
else
loop (arr1, arr2, false, idigit_max, succ idigit)
end
else
let
var all_expended : bool
in
sort_by_digit<a><tk> (arr2, arr1, n, all_expended,
8 * idigit);
if all_expended then
let
val _ =
$extfcall (ptr, "memcpy", addr@ arr1, addr@ arr2,
sizeof<a> * n)
in
end
else
loop (arr1, arr2, true, idigit_max, succ idigit)
end
in
loop (arr1, arr2, true, sz2i sizeof<g1uint tk>, 0)
end
#define SIZE_THRESHOLD 256
extern praxi
unsafe_cast_array
{a : vt@ype}
{b : vt@ype}
{n : int}
(arr : &array (b, n) >> array (a, n))
:<prf> void
implement {a} {tk}
g0uint_radix_sort {n} (arr, n) =
if n <> 0 then
let
prval () = lemma_array_param arr
fn
sort {n : pos}
(arr1 : &array (a, n) >> _,
arr2 : &array (a, n) >> _,
n : size_t n)
:<!wrt> void =
g0uint_sort<a><tk> (arr1, arr2, n)
in
if n <= SIZE_THRESHOLD then
let
var arr2 : array (a, SIZE_THRESHOLD)
prval @(pf_left, pf_right) =
array_v_split {a?} {..} {SIZE_THRESHOLD} {n} (view@ arr2)
prval () = view@ arr2 := pf_left
prval () = unsafe_cast_array{a} arr2
val () = sort (arr, arr2, n)
prval () = unsafe_cast_array{a?} arr2
prval () = view@ arr2 :=
array_v_unsplit (view@ arr2, pf_right)
in
end
else
let
val @(pf_arr2, pfgc_arr2 | p_arr2) = array_ptr_alloc<a> n
macdef arr2 = !p_arr2
prval () = unsafe_cast_array{a} arr2
val () = sort (arr, arr2, n)
prval () = unsafe_cast_array{a?} arr2
val () = array_ptr_free (pf_arr2, pfgc_arr2 | p_arr2)
in
end
end
(*------------------------------------------------------------------*)
(* An implementation of the remove_dups template function, which also
sorts the elements. *)
implement {tk}
remove_dups {n} (src, n, dst, m) =
if n = i2sz 0 then
m := i2sz 0
else
let
prval () = lemma_arrayref_param src (* Prove 0 <= n. *)
(* Sort a copy of src. *)
val arrptr = arrayref_copy (src, n)
val @(pf_arr | p_arr) = arrayptr_takeout_viewptr arrptr
val () = g0uint_radix_sort<g0uint tk><tk> (!p_arr, n)
prval () = arrayptr_addback (pf_arr | arrptr)
(* Copy only the first element of each run of equals. *)
val () = dst[0] := arrptr[0]
fun
loop {i : int | 1 <= i; i <= n}
{j : int | 1 <= j; j <= i}
.<n - i>.
(arrptr : !arrayptr (g0uint tk, n),
i : size_t i,
j : size_t j)
: [m : int | 1 <= m; m <= n]
size_t m =
if i = n then
j
else if arrptr[pred i] = arrptr[i] then
loop (arrptr, succ i, j)
else
begin
dst[j] := arrptr[i];
loop (arrptr, succ i, succ j)
end
val () = m := loop (arrptr, i2sz 1, i2sz 1)
val () = arrayptr_free arrptr
in
end
(*------------------------------------------------------------------*)
(* A demonstration. *)
implement
main0 () =
let
implement
g0uint_radix_sort$key<uint><uintknd> (arr, i) =
arr[i]
val src =
arrayref_make_list<uint>
(10, $list (1U, 3U, 2U, 5U, 1U, 1U, 4U, 4U, 2U, 3U))
val dst = arrayref_make_elt<uint> (i2sz 10, 123456789U)
var m : size_t
in
remove_dups<uintknd> (src, i2sz 10, dst, m);
let
prval [m : int] EQINT () = eqint_make_guint m
var i : natLte m
in
for (i := 0; i2sz i <> m; i := succ i)
print! (" ", dst[i]);
println! ()
end
end
(*------------------------------------------------------------------*)
- Output:
1 2 3 4 5
ATS2 implementation using a hash table
The speed of this method depends on the speed of the hash table.
(* Remove duplicate elements.
Elements already seen are put into a hash table. *)
#include "share/atspre_staload.hats"
(* Use hash tables from the libats/ML library. *)
staload "libats/ML/SATS/hashtblref.sats"
staload _ = "libats/ML/DATS/hashtblref.dats"
staload _ = "libats/DATS/hashfun.dats"
staload _ = "libats/DATS/hashtbl_chain.dats"
staload _ = "libats/DATS/linmap_list.dats"
(* How the remove_dups template function will be called. *)
extern fn {key, a : t@ype}
remove_dups
{n : int}
(key : a -<cloref> key,
src : arrayref (a, n),
n : size_t n,
dst : arrayref (a, n),
m : &size_t? >> size_t m)
: #[m : nat | m <= n]
void
implement {key, a}
remove_dups {n} (key, src, n, dst, m) =
if n = i2sz 0 then
m := i2sz 0
else
let
prval () = lemma_arrayref_param src (* Prove 0 <= n. *)
fun
loop {i : nat | i <= n}
{j : nat | j <= i}
.<n - i>.
(ht : hashtbl (key, a),
i : size_t i,
j : size_t j)
: [m : nat | m <= n]
size_t m =
if i = n then
j
else
let
val x = src[i]
val k = key x
in
case+ hashtbl_search<key, a> (ht, k) of
| ~ None_vt () =>
begin (* An element not yet encountered. Copy it. *)
hashtbl_insert_any<key, a> (ht, k, x);
dst[j] := x;
loop (ht, succ i, succ j)
end
| ~ Some_vt _ =>
begin (* An element already encountered. Skip it. *)
loop (ht, succ i, j)
end
end;
in
m := loop (hashtbl_make_nil<key, a> (i2sz 1024),
i2sz 0, i2sz 0)
end
implement (* A demonstration. *)
main0 () =
let
val src =
arrayref_make_list<string>
(10, $list ("a", "c", "b", "e", "a",
"a", "d", "d", "b", "c"))
val dst = arrayref_make_elt<string> (i2sz 10, "?")
var m : size_t
in
remove_dups<string, string> (lam s => s, src, i2sz 10, dst, m);
let
prval [m : int] EQINT () = eqint_make_guint m
var i : natLte m
in
for (i := 0; i2sz i <> m; i := succ i)
print! (" ", dst[i]);
println! ()
end
end
- Output:
a c b e d
ATS2 implementation for values containing a mutable seen flag
This method runs O(n) in the number of elements. It can be useful when you are working with references to complicated data structures. It works only if the array contains references to structures, rather than the structures themselves.
This implementation is for non-linear types only and happens to demonstrate "ordinary" imperative programming in ATS2: without dependent types, proofs, etc. The code is still safe against over-running array boundaries, but the safety is enforced by run-time checks rather than proofs.
(* Remove duplicate elements.
This implementation is for elements that contain a "this has been
seen" flag. It is O(n) in the number of elements.
Also, this implementation demonstrates that imperative programming,
without dependent types or proofs, is possible in ATS. *)
#include "share/atspre_staload.hats"
(* A tuple in the heap. *)
typedef seen_or_not (a : t@ype+) = '(a, ref bool)
(* How the remove_dups function will be called. *)
extern fn {a : t@ype}
remove_dups
(given_data : arrszref (seen_or_not a),
space_for_result : arrszref (seen_or_not a),
num_of_unique_elems : &size_t? >> size_t)
: void
implement {a}
remove_dups (given_data, space_for_result, num_of_unique_elems) =
let
macdef seen (i) = given_data[,(i)].1
var i : size_t
var j : size_t
in
(* Clear all the "seen" flags. *)
for (i := i2sz 0; i <> size given_data; i := succ i)
!(seen i) := false;
(* Loop through given_data, copying (pointers to) any values that
have not yet been seen. *)
j := i2sz 0;
for (i := i2sz 0; i <> size given_data; i := succ i)
if !(seen i) then
() (* Skip any element that has already been seen. *)
else
begin
!(seen i) := true; (* Mark the element as seen. *)
space_for_result[j] := given_data[i];
j := succ j
end;
num_of_unique_elems := j
end
implement (* A demonstration. *)
main0 () =
let
(* Define some values. *)
val a = '("a", ref<bool> false)
val b = '("b", ref<bool> false)
val c = '("c", ref<bool> false)
val d = '("d", ref<bool> false)
val e = '("e", ref<bool> false)
(* Fill an array with values. *)
val data =
arrszref_make_list ($list (a, c, b, e, a, a, d, d, b, c))
(* Allocate storage for the result. *)
val unique_elems = arrszref_make_elt (i2sz 10, a)
var num_of_unique_elems : size_t
var i : size_t
in
(* Remove duplicates. *)
remove_dups<string> (data, unique_elems, num_of_unique_elems);
(* Print the results. *)
for (i := i2sz 0; i <> num_of_unique_elems; i := succ i)
print! (" ", unique_elems[i].0);
println! ()
end
- Output:
a c b e d
AutoHotkey
Built in Sort has an option to remove duplicates
a = 1,2,1,4,5,2,15,1,3,4
Sort, a, a, NUD`,
MsgBox % a ; 1,2,3,4,5,15
AWK
We produce an array a with duplicates from a string; then index a second array b with the contents of a, so that duplicates make only one entry; then produce a string with the keys of b, which is finally output.
$ awk 'BEGIN{split("a b c d c b a",a);for(i in a)b[a[i]]=1;r="";for(i in b)r=r" "i;print r}'
a b c d
BASIC
ANSI BASIC
100 REM Remove duplicate elements
110 DIM DataArray(1 TO 7), ResultArray(1 TO 7)
120 ! Set the data.
130 FOR I = 1 TO 7
140 READ DataArray(I)
150 NEXT I
160 ! Remove duplicates
170 LET ResultArray(1) = DataArray(1)
180 LET LastResultIndex = 1
190 LET Position = 1
200 DO WHILE Position < UBOUND(DataArray)
210 LET Position = Position + 1
220 LET IsNewNumber = -1
230 FOR ResultIndex = 1 TO LastResultIndex
240 IF DataArray(Position) = ResultArray(ResultIndex) THEN
250 LET IsNewNumber = 0
260 EXIT FOR
270 END IF
280 NEXT ResultIndex
290 IF IsNewNumber = -1 THEN
300 LET LastResultIndex = LastResultIndex + 1
310 LET ResultArray(LastResultIndex) = DataArray(Position)
320 END IF
330 LOOP
340 FOR ResultIndex = 1 TO LastResultIndex
350 PRINT ResultArray(ResultIndex)
360 NEXT ResultIndex
370 DATA 1, 2, 2, 3, 4, 5, 5
380 END
- Output:
1 2 3 4 5
Applesoft BASIC
100 DIM L$(15)
110 L$(0) = "NOW"
120 L$(1) = "IS"
130 L$(2) = "THE"
140 L$(3) = "TIME"
150 L$(4) = "FOR"
160 L$(5) = "ALL"
170 L$(6) = "GOOD"
180 L$(7) = "MEN"
190 L$(8) = "TO"
200 L$(9) = "COME"
210 L$(10) = "TO"
220 L$(11) = "THE"
230 L$(12) = "AID"
240 L$(13) = "OF"
250 L$(14) = "THE"
260 L$(15) = "PARTY."
300 N = 15
310 GOSUB 400
320 FOR I = 0 TO N
330 PRINT L$(I) " " ;
340 NEXT
350 PRINT
360 END
400 REMREMOVE DUPLICATES
410 FOR I = N TO 1 STEP -1
420 I$ = L$(I)
430 FOR J = 0 TO I - 1
440 EQ = I$ = L$(J)
450 IF NOT EQ THEN NEXT J
460 IF EQ THEN GOSUB 500
470 NEXT I
480 RETURN
500 REMREMOVE ELEMENT
510 L$(I) = L$(N)
520 L$(N) = ""
530 N = N - 1
540 RETURN
BASIC256
arraybase 1
max = 10
dim res(max)
dim dat(max)
dat[1] = 1: dat[2] = 2: dat[3] = 1: dat[4] = 4: dat[5] = 5
dat[6] = 2: dat[7] = 15: dat[8] = 1: dat[9] = 3: dat[10] = 4
res[1] = dat[1]
cont = 1
posic = 1
while posic < max
posic += 1
esnuevo = 1
indice = 1
while indice <= cont and esnuevo = 1
if dat[posic] = res[indice] then esnuevo = 0
indice += 1
end while
if esnuevo = 1 then
cont += 1
res[cont] = dat[posic]
end if
end while
for i = 1 to cont
print res[i]; " ";
next i
end
BBC BASIC
DIM list$(15)
list$() = "Now", "is", "the", "time", "for", "all", "good", "men", \
\ "to", "come", "to", "the", "aid", "of", "the", "party."
num% = FNremoveduplicates(list$())
FOR i% = 0 TO num%-1
PRINT list$(i%) " " ;
NEXT
PRINT
END
DEF FNremoveduplicates(l$())
LOCAL i%, j%, n%, i$
n% = 1
FOR i% = 1 TO DIM(l$(), 1)
i$ = l$(i%)
FOR j% = 0 TO i%-1
IF i$ = l$(j%) EXIT FOR
NEXT
IF j%>=i% l$(n%) = i$ : n% += 1
NEXT
= n%
- Output:
Now is the time for all good men to come aid of party.
FreeBASIC
' FB 1.05.0 Win64
Sub removeDuplicates(a() As Integer, b() As Integer)
Dim lb As Integer = LBound(a)
Dim ub As Integer = UBound(a)
If ub = -1 Then Return '' empty array
Redim b(lb To ub)
b(lb) = a(lb)
Dim count As Integer = 1
Dim unique As Boolean
For i As Integer = lb + 1 To ub
unique = True
For j As Integer = lb to i - 1
If a(i) = a(j) Then
unique = False
Exit For
End If
Next j
If unique Then
b(lb + count) = a(i)
count += 1
End If
Next i
If count > 0 Then Redim Preserve b(lb To lb + count - 1)
End Sub
Dim a(1 To 10) As Integer = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4}
Dim b() As Integer
removeDuplicates a(), b()
For i As Integer = LBound(b) To UBound(b)
Print b(i); " ";
Next
Print
Print "Press any key to quit"
Sleep
- Output:
1 2 4 5 15 3
FutureBasic
include "NSLog.incl"
CFArrayRef array, unique
OrderedSetRef ordered
array = @[@"A", @"B", @"C", @"B", @"A", @"C", @"A", @"C", @"A", @"B", @"C"]
ordered = fn OrderedSetWithArray( array )
NSLog( @"%@", fn OrderedSetArray( ordered ) )
HandleEvents
- Output:
( A, B, C )
Gambas
Click this link to run this code
Public Sub Main()
Dim sString As String[] = Split("Now is the time for all the good men to come to the aid of the good party 1 2 1 3 3 3 2 1 1 2 3 4 33 2 5 4 333 5", " ")
Dim sFix As New String[]
Dim sTemp As String
For Each sTemp In sString
sTemp &= " "
If InStr(sFix.Join(" ") & " ", sTemp) Then Continue
sFix.Add(Trim(sTemp))
Next
Print sFix.Join(" ")
End
Output:
Now is the time for all good men to come aid of party 1 2 3 4 33 5 333
GW-BASIC
10 ' Remove Duplicates
20 OPTION BASE 1
30 LET MAXI% = 7
40 DIM D(7), R(7): ' data, result
50 ' Set the data.
60 FOR I% = 1 TO 7
70 READ D(I%)
80 NEXT I%
90 ' Remove duplicates.
100 LET R(1) = D(1)
110 LET LRI% = 1: ' last index of result
120 LET P% = 1: ' position
130 WHILE P% < MAXI%
140 LET P% = P% + 1
150 LET ISNEW = 1: ' is a new number?
160 LET RI% = 1: ' current index of result
170 WHILE (RI% <= LRI%) AND ISNEW
180 IF D(P%) = R(RI%) THEN LET ISNEW = 0
190 LET RI% = RI% + 1
200 WEND
210 IF ISNEW THEN LET LRI% = LRI% + 1: LET R(LRI%) = D(P%)
220 WEND
230 FOR RI% = 1 TO LRI%
240 PRINT R(RI%)
250 NEXT RI%
260 END
1000 DATA 1, 2, 2, 3, 4, 5, 5
- Output:
1 2 3 4 5
IS-BASIC
100 PROGRAM "RemoveDu.bas"
110 RANDOMIZE
120 NUMERIC ARR(1 TO 20),TOP
130 LET TOP=FILL(ARR)
140 CALL WRITE(ARR,TOP)
150 LET TOP=REMOVE(ARR)
160 CALL WRITE(ARR,TOP)
170 DEF WRITE(REF A,N)
180 FOR I=1 TO N
190 PRINT A(I);
200 NEXT
210 PRINT
220 END DEF
230 DEF FILL(REF A)
240 LET FILL=UBOUND(A):LET A(LBOUND(A))=1
250 FOR I=LBOUND(A)+1 TO UBOUND(A)
260 LET A(I)=A(I-1)+RND(3)
270 NEXT
280 END DEF
290 DEF REMOVE(REF A)
300 LET ST=0
310 FOR I=LBOUND(A)+1 TO UBOUND(A)
320 IF A(I-1)=A(I) THEN LET ST=ST+1
330 IF ST>0 THEN LET A(I-ST)=A(I)
340 NEXT
350 LET REMOVE=UBOUND(A)-ST
360 END DEF
- Output:
START 1 1 2 4 5 7 9 10 12 14 16 16 16 17 18 20 20 22 23 23 1 2 4 5 7 9 10 12 14 16 17 18 20 22 23 ok START 1 2 4 5 5 5 7 8 9 9 10 10 10 12 14 15 17 17 18 20 1 2 4 5 7 8 9 10 12 14 15 17 18 20 ok START 1 3 3 4 5 6 8 10 11 12 14 16 16 16 16 18 18 19 21 21 1 3 4 5 6 8 10 11 12 14 16 18 19 21 ok START 1 3 3 4 5 5 7 9 11 13 13 14 16 17 17 18 19 19 20 21 1 3 4 5 7 9 11 13 14 16 17 18 19 20 21 ok START 1 2 3 5 5 6 6 7 8 10 12 14 15 17 17 19 21 23 25 25 1 2 3 5 6 7 8 10 12 14 15 17 19 21 23 25 ok
Liberty BASIC
LB has arrays, but here the elements are stored in a space-separated string. Template:Works sith
a$ =" 1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19 "
print "Original set of elements = ["; a$; "]"
b$ =removeDuplicates$( a$)
print "With duplicates removed = ["; b$; "]"
end
function removeDuplicates$( in$)
o$ =" "
i =1
do
term$ =word$( in$, i, " ")
if instr( o$, " "; term$; " ") =0 and term$ <>" " then o$ =o$ +term$ +" "
i =i +1
loop until term$ =""
removeDuplicates$ =o$
end function
- Output:
Original set of elements = [ 1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19 ] With duplicates removed = [ 1 $23.19 2 elbow 3 Bork 4 ]
Microsoft Small Basic
' Set the data.
dataArray[1] = 1
dataArray[2] = 2
dataArray[3] = 2
dataArray[4] = 3
dataArray[5] = 4
dataArray[6] = 5
dataArray[7] = 5
resultArray[1] = dataArray[1]
lastResultIndex = 1
position = 1
While position < Array.GetItemCount(dataArray)
position = position + 1
isNewNumber = 1 ' logical 1
resultIndex = 1
While (resultIndex <= lastResultIndex) And isNewNumber = 1
If dataArray[position] = resultArray[resultIndex] Then
isNewNumber = 0
EndIf
resultIndex = resultIndex + 1
EndWhile
If isNewNumber = 1 Then
lastResultIndex = lastResultIndex + 1
resultArray[lastResultIndex] = dataArray[position]
EndIf
EndWhile
For resultIndex = 1 To lastResultIndex
TextWindow.WriteLine(resultArray[resultIndex])
EndFor
PureBasic
Task solved with the built in Hash Table which are called Maps in PureBasic
NewMap MyElements.s()
For i=0 To 9 ;Mark 10 items at random, causing high risk of duplication items.
x=Random(9)
t$="Number "+str(x)+" is marked"
MyElements(str(x))=t$ ; Add element 'X' to the hash list or overwrite if already included.
Next
ForEach MyElements()
Debug MyElements()
Next
Output may look like this, e.g. duplicated items are automatically removed as they have the same hash value.
Number 0 is marked Number 2 is marked Number 5 is marked Number 6 is marked
Run BASIC
a$ = "2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2"
for i = 1 to len(a$)
a1$ = word$(a$,i)
if a1$ = "" then exit for
for i1 = 1 to len(b$)
if a1$ = word$(b$,i1) then [nextWord]
next i1
b$ = b$ + a1$ + " "
[nextWord]
next i
print "Dups:";a$
print "No Dups:";b$
Dups:2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2 No Dups:2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 0 4.4
True BASIC
OPTION BASE 1
LET max = 10
DIM dat(10), res(10)
FOR i = 1 TO max
READ dat(i)
NEXT i
DATA 1, 2, 1, 4, 5, 2, 15, 1, 3, 4
LET res(1) = dat(1)
LET count = 1
LET posic = 1
DO WHILE posic < max
LET posic = posic + 1
LET esnuevo = 1
LET indice = 1
DO WHILE (indice <= count) AND esnuevo = 1
IF dat(posic) = res(indice) THEN LET esnuevo = 0
LET indice = indice + 1
LOOP
IF esnuevo = 1 THEN
LET count = count + 1
LET res(count) = dat(posic)
END IF
LOOP
FOR i = 1 TO count
PRINT res(i);
NEXT i
END
VBA
Hash Table Approach Input list (variant : Long, Double, Boolean and Strings) : Array(1.23456789101112E+16, True, False, True, "Alpha", 1, 235, 4, 1.25, 1.25, "Beta", 1.23456789101112E+16, "Delta", "Alpha", "Charlie", 1, 2, "Foxtrot", "Foxtrot", "Alpha", 235)
Option Explicit
Sub Main()
Dim myArr() As Variant, i As Long
myArr = Remove_Duplicate(Array(1.23456789101112E+16, True, False, True, "Alpha", 1, 235, 4, 1.25, 1.25, "Beta", 1.23456789101112E+16, "Delta", "Alpha", "Charlie", 1, 2, "Foxtrot", "Foxtrot", "Alpha", 235))
'return :
For i = LBound(myArr) To UBound(myArr)
Debug.Print myArr(i)
Next
End Sub
Private Function Remove_Duplicate(Arr As Variant) As Variant()
Dim myColl As New Collection, Temp() As Variant, i As Long, cpt As Long
ReDim Temp(UBound(Arr))
For i = LBound(Arr) To UBound(Arr)
On Error Resume Next
myColl.Add CStr(Arr(i)), CStr(Arr(i))
If Err.Number > 0 Then
On Error GoTo 0
Else
Temp(cpt) = Arr(i)
cpt = cpt + 1
End If
Next i
ReDim Preserve Temp(cpt - 1)
Remove_Duplicate = Temp
End Function
- Output:
1.23456789101112E+16 True False Alpha 1 235 4 1.25 Beta Delta Charlie 2 Foxtrot
VBScript
Hash Table Approach
Function remove_duplicates(list)
arr = Split(list,",")
Set dict = CreateObject("Scripting.Dictionary")
For i = 0 To UBound(arr)
If dict.Exists(arr(i)) = False Then
dict.Add arr(i),""
End If
Next
For Each key In dict.Keys
tmp = tmp & key & ","
Next
remove_duplicates = Left(tmp,Len(tmp)-1)
End Function
WScript.Echo remove_duplicates("a,a,b,b,c,d,e,d,f,f,f,g,h")
- Output:
a,b,c,d,e,f,g,h
Yabasic
data "Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "to", "the", "aid", "of", "the", "party.", ""
do
read p$
if p$ = "" break
if not instr(r$, p$) r$ = r$ + p$ + " "
loop
print r$
BQN
⍷ 2‿4‿9‿7‿3‿7‿4‿1‿9‿2‿5‿7‿2‿2‿8‿9‿6‿6‿5‿8
- Output:
⟨ 2 4 9 7 3 1 5 8 6 ⟩
Bracmat
Here are three solutions. The first one (A) uses a hash table, the second (B) uses a pattern for spotting the elements that have a copy further on in the list and only adds those elements to the answer that don't have copies further on. The third solution (C) utilises an mechanism that is very typical of Bracmat, namely that sums (and also products) always are transformed to a normalised form upon evaluation. Normalisation means that terms are ordered in a unique way and that terms that are equal, apart from a numerical factor, are replaced by a single term with a numerical factor that is the sum of the numerical factors of each term. The answer is obtained by replacing all numerical factors by 1
as the last step.
The list contains atoms and also a few non-atomic expressions. The hash table needs atomic keys, so we apply the str
function when searching and inserting elements.
2 3 5 7 11 13 17 19 cats 222 (-100.2) "+11" (1.1) "+7" (7.) 7 5 5 3 2 0 (4.4) 2:?LIST
(A=
( Hashing
= h elm list
. new$hash:?h
& whl
' ( !arg:%?elm ?arg
& ( (h..find)$str$!elm
| (h..insert)$(str$!elm.!elm)
)
)
& :?list
& (h..forall)
$ (
= .!arg:(?.?arg)&!arg !list:?list
)
& !list
)
& put$("Solution A:" Hashing$!LIST \n,LIN)
);
(B=
( backtracking
= answr elm
. :?answr
& !arg
: ?
( %?`elm
?
( !elm ?
| &!answr !elm:?answr
)
& ~
)
| !answr
)
& put$("Solution B:" backtracking$!LIST \n,LIN)
);
(C=
( summing
= sum car LIST
. !arg:?LIST
& 0:?sum
& whl
' ( !LIST:%?car ?LIST
& (.!car)+!sum:?sum
)
& whl
' ( !sum:#*(.?el)+?sum
& !el !LIST:?LIST
)
& !LIST
)
& put$("Solution C:" summing$!LIST \n,LIN)
);
( !A
& !B
& !C
&
)
Only solution B produces a list with the same order of elements as in the input.
Solution A: 19 (4.4) 17 11 13 (1.1) (7.) 222 +11 7 5 3 2 0 cats (-100.2) +7 Solution B: 11 13 17 19 cats 222 (-100.2) +11 (1.1) +7 (7.) 7 5 3 0 (4.4) 2 Solution C: (7.) (4.4) (1.1) (-100.2) cats 222 19 17 13 11 7 5 3 2 0 +7 +11
Brat
some_array = [1 1 2 1 'redundant' [1 2 3] [1 2 3] 'redundant']
unique_array = some_array.unique
C
O(n^2) version, using linked lists
Since there's no way to know ahead of time how large the new data structure will need to be, we'll return a linked list instead of an array.
#include <stdio.h>
#include <stdlib.h>
struct list_node {int x; struct list_node *next;};
typedef struct list_node node;
node * uniq(int *a, unsigned alen)
{if (alen == 0) return NULL;
node *start = malloc(sizeof(node));
if (start == NULL) exit(EXIT_FAILURE);
start->x = a[0];
start->next = NULL;
for (int i = 1 ; i < alen ; ++i)
{node *n = start;
for (;; n = n->next)
{if (a[i] == n->x) break;
if (n->next == NULL)
{n->next = malloc(sizeof(node));
n = n->next;
if (n == NULL) exit(EXIT_FAILURE);
n->x = a[i];
n->next = NULL;
break;}}}
return start;}
int main(void)
{int a[] = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4};
for (node *n = uniq(a, 10) ; n != NULL ; n = n->next)
printf("%d ", n->x);
puts("");
return 0;}
- Output:
1 2 4 5 15 3
O(n^2) version, pure arrays
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
/* Returns `true' if element `e' is in array `a'. Otherwise, returns `false'.
* Checks only the first `n' elements. Pure, O(n).
*/
bool elem(int *a, size_t n, int e)
{
for (size_t i = 0; i < n; ++i)
if (a[i] == e)
return true;
return false;
}
/* Removes the duplicates in array `a' of given length `n'. Returns the number
* of unique elements. In-place, order preserving, O(n ^ 2).
*/
size_t nub(int *a, size_t n)
{
size_t m = 0;
for (size_t i = 0; i < n; ++i)
if (!elem(a, m, a[i]))
a[m++] = a[i];
return m;
}
/* Out-place version of `nub'. Pure, order preserving, alloc < n * sizeof(int)
* bytes, O(n ^ 2).
*/
size_t nub_new(int **b, int *a, size_t n)
{
int *c = malloc(n * sizeof(int));
memcpy(c, a, n * sizeof(int));
int m = nub(c, n);
*b = malloc(m * sizeof(int));
memcpy(*b, c, m * sizeof(int));
free(c);
return m;
}
int main(void)
{
int a[] = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4};
int *b;
size_t n = nub_new(&b, a, sizeof(a) / sizeof(a[0]));
for (size_t i = 0; i < n; ++i)
printf("%d ", b[i]);
puts("");
free(b);
return 0;
}
- Output:
1 2 4 5 15 3
Sorting method
Using qsort and return uniques in-place:
#include <stdio.h>
#include <stdlib.h>
int icmp(const void *a, const void *b)
{
#define _I(x) *(const int*)x
return _I(a) < _I(b) ? -1 : _I(a) > _I(b);
#undef _I
}
/* filter items in place and return number of uniques. if a separate
list is desired, duplicate it before calling this function */
int uniq(int *a, int len)
{
int i, j;
qsort(a, len, sizeof(int), icmp);
for (i = j = 0; i < len; i++)
if (a[i] != a[j]) a[++j] = a[i];
return j + 1;
}
int main()
{
int x[] = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4};
int i, len = uniq(x, sizeof(x) / sizeof(x[0]));
for (i = 0; i < len; i++) printf("%d\n", x[i]);
return 0;
}
- Output:
1 2 3 4 5 15
C#
int[] nums = { 1, 1, 2, 3, 4, 4 };
List<int> unique = new List<int>();
foreach (int n in nums)
if (!unique.Contains(n))
unique.Add(n);
int[] nums = {1, 1, 2, 3, 4, 4};
int[] unique = nums.Distinct().ToArray();
C++
This version uses std::set, which requires its element type be comparable using the < operator.
#include <set>
#include <iostream>
using namespace std;
int main() {
typedef set<int> TySet;
int data[] = {1, 2, 3, 2, 3, 4};
TySet unique_set(data, data + 6);
cout << "Set items:" << endl;
for (TySet::iterator iter = unique_set.begin(); iter != unique_set.end(); iter++)
cout << *iter << " ";
cout << endl;
}
This version uses hash_set, which is part of the SGI extension to the Standard Template Library. It is not part of the C++ standard library. It requires that its element type have a hash function.
#include <ext/hash_set>
#include <iostream>
using namespace std;
int main() {
typedef __gnu_cxx::hash_set<int> TyHash;
int data[] = {1, 2, 3, 2, 3, 4};
TyHash unique_set(data, data + 6);
cout << "Set items:" << endl;
for (TyHash::iterator iter = unique_set.begin(); iter != unique_set.end(); iter++)
cout << *iter << " ";
cout << endl;
}
This version uses unordered_set, which is part of the TR1, which is likely to be included in the next version of C++. It is not part of the C++ standard library. It requires that its element type have a hash function.
#include <tr1/unordered_set>
#include <iostream>
using namespace std;
int main() {
typedef tr1::unordered_set<int> TyHash;
int data[] = {1, 2, 3, 2, 3, 4};
TyHash unique_set(data, data + 6);
cout << "Set items:" << endl;
for (TyHash::iterator iter = unique_set.begin(); iter != unique_set.end(); iter++)
cout << *iter << " ";
cout << endl;
}
Alternative method working directly on the array:
#include <iostream>
#include <iterator>
#include <algorithm>
// helper template
template<typename T> T* end(T (&array)[size]) { return array+size; }
int main()
{
int data[] = { 1, 2, 3, 2, 3, 4 };
std::sort(data, end(data));
int* new_end = std::unique(data, end(data));
std::copy(data, new_end, std::ostream_iterator<int>(std::cout, " ");
std::cout << std::endl;
}
Using sort, unique, and erase on a vector.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> data = {1, 2, 3, 2, 3, 4};
std::sort(data.begin(), data.end());
data.erase(std::unique(data.begin(), data.end()), data.end());
for(int& i: data) std::cout << i << " ";
std::cout << std::endl;
return 0;
}
CafeOBJ
The parametrized module NO-DUP-LIST(ELEMENTS :: TRIV) defines the signature of a space separated list structure. The removal of duplicates is handled by the equational properties listed after the signature in brackets {}. There is no user written code in module NO-DUP-LIST. The binary operation (_ _) is associative, commutative, and idempotent, meaning (x , x) = x. This list structure does not permit duplicates, they are removed during evaluation (called reduction in CafeOBJ). Using this module we can perform set union, just by evaluating two lists e.g:
red (1 2 3 4) (3 2 1 5) .
--> (4 5 1 2 3):Int
mod! NO-DUP-LIST(ELEMENTS :: TRIV) {
op __ : Elt Elt -> Elt { comm assoc idem assoc }
}
-- Runs on Version 1.5.1(PigNose0.99) of CafeOBJ
-- The tests are performed after opening instantiated NO-DUP-LIST with various concrete types.
-- Test on lists of INT
open NO-DUP-LIST(INT) .
red 2 1 2 1 2 1 3 .
-- Gives (2 1 3):Int
open NO-DUP-LIST(INT) .
reduce 1 1 2 1 1 .
close
open NO-DUP-LIST(CHARACTER) .
reduce 'a' 'b' 'a' 'a' .
close
open NO-DUP-LIST(STRING) .
reduce "abc" "def" "abc" "abc" "abc" .
close
How does work?
The evaluation automatically uses right associativity. So starting with:
(1 1 2 1 1)
The system places appropriate brackets on the entire expression:
(1 ((1 2) (1 1)))
Idempotency is applied at rightmost inner brackets: We get rewrite (1 1) -> 1. The term is now:
(1 ((1 2) 1))
Any further occurrence of 1 will be removed.
Idempotency is applied at inner brackets (1 2) . We get rewrite (1 2) -> 2 . The term is now:
(1 (2 1))
By already established idempotency we finally get
(2 1)
Ceylon
<String|Integer>[] data = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"];
<String|Integer>[] unique = HashSet { *data }.sequence();
Clojure
user=> (distinct [1 3 2 9 1 2 3 8 8 1 0 2])
(1 3 2 9 8 0)
user=>
CoffeeScript
data = [ 1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d" ]
set = []
set.push i for i in data when not (i in set)
console.log data
console.log set
- Output:
[ 1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd' ] [ 1, 2, 3, 'a', 'b', 'c', 4, 'd' ]
Common Lisp
To remove duplicates non-destructively:
(remove-duplicates '(1 3 2 9 1 2 3 8 8 1 0 2))
> (9 3 8 1 0 2)
Or, to remove duplicates in-place:
(delete-duplicates '(1 3 2 9 1 2 3 8 8 1 0 2))
> (9 3 8 1 0 2)
Crystal
Copied and modified from the Ruby version.
ary = [1, 1, 2, 2, "a", [1, 2, 3], [1, 2, 3], "a"]
p ary.uniq
[1, 2, "a", [1, 2, 3]]
D
void main() {
import std.stdio, std.algorithm;
[1, 3, 2, 9, 1, 2, 3, 8, 8, 1, 0, 2]
.sort()
.uniq
.writeln;
}
- Output:
[0, 1, 2, 3, 8, 9]
Using an associative array:
void main() {
import std.stdio;
immutable data = [1, 3, 2, 9, 1, 2, 3, 8, 8, 1, 0, 2];
bool[int] hash;
foreach (el; data)
hash[el] = true;
hash.byKey.writeln;
}
- Output:
[8, 0, 1, 9, 2, 3]
Like code D#1, but with an array returned:
void main()
{
import std.stdio, std.algorithm, std.array;
auto a = [5,4,32,7,6,4,2,6,0,8,6,9].sort.uniq.array;
a.writeln;
}
- Output:
[0, 2, 4, 5, 6, 7, 8, 9, 32]
Delphi
Generics were added in Delphi2009.
program RemoveDuplicateElements;
{$APPTYPE CONSOLE}
uses Generics.Collections;
var
i: Integer;
lIntegerList: TList<Integer>;
const
INT_ARRAY: array[1..7] of Integer = (1, 2, 2, 3, 4, 5, 5);
begin
lIntegerList := TList<Integer>.Create;
try
for i in INT_ARRAY do
if not lIntegerList.Contains(i) then
lIntegerList.Add(i);
for i in lIntegerList do
Writeln(i);
finally
lIntegerList.Free;
end;
end.
- Output:
1 2 3 4 5
Déjà Vu
}
for item in [ 1 10 1 :hi :hello :hi :hi ]:
@item
!. keys set{
- Output:
[ 1 :hello 10 :hi ]
E
[1,2,3,2,3,4].asSet().getElements()
EasyLang
a[] = [ 1 2 1 4 5 2 15 1 3 4 ]
for a in a[]
found = 0
for b in b[]
if a = b
found = 1
break 1
.
.
if found = 0
b[] &= a
.
.
print b[]
ECL
inNumbers := DATASET([{1},{2},{3},{4},{1},{1},{7},{8},{9},{9},{0},{0},{3},{3},{3},{3},{3}], {INTEGER Field1});
DEDUP(SORT(inNumbers,Field1));
- Output:
0 1 2 3 4 7 8 9
Elena
ELENA 6.x :
import extensions;
import system'collections;
import system'routines;
public program()
{
var nums := new int[]{1,1,2,3,4,4};
auto unique := new Map<int, int>();
nums.forEach::(n){ unique[n] := n };
console.printLine(unique.MapValues.asEnumerable())
}
- Output:
1,2,3,4
Ecstasy
module RetainUniqueValues {
void run() {
Int[] array = [1, 2, 3, 2, 1, 2, 3, 4, 5, 3, 2, 1];
array = array.distinct().toArray();
@Inject Console console;
console.print($"result={array}");
}
}
- Output:
result=[1, 2, 3, 4, 5]
Elixir
Elixir has an Enum.uniq
built-in function.
defmodule RC do
# Set approach
def uniq1(list), do: MapSet.new(list) |> MapSet.to_list
# Sort approach
def uniq2(list), do: Enum.sort(list) |> Enum.dedup
# Go through the list approach
def uniq3(list), do: uniq3(list, [])
defp uniq3([], res), do: Enum.reverse(res)
defp uniq3([h|t], res) do
if h in res, do: uniq3(t, res), else: uniq3(t, [h | res])
end
end
num = 10000
max = div(num, 10)
list = for _ <- 1..num, do: :rand.uniform(max)
funs = [&Enum.uniq/1, &RC.uniq1/1, &RC.uniq2/1, &RC.uniq3/1]
Enum.each(funs, fn fun ->
result = fun.([1,1,2,1,'redundant',1.0,[1,2,3],[1,2,3],'redundant',1.0])
:timer.tc(fn ->
Enum.each(1..100, fn _ -> fun.(list) end)
end)
|> fn{t,_} -> IO.puts "#{inspect fun}:\t#{t/1000000}\t#{inspect result}" end.()
end)
- Output:
&Enum.uniq/1: 0.296 [1, 2, 'redundant', 1.0, [1, 2, 3]] &RC.uniq1/1: 0.686 [1, 2, 1.0, [1, 2, 3], 'redundant'] &RC.uniq2/1: 0.921 [1, 1.0, 2, [1, 2, 3], 'redundant'] &RC.uniq3/1: 1.497 [1, 2, 'redundant', 1.0, [1, 2, 3]]
Erlang
List = [1, 2, 3, 2, 2, 4, 5, 5, 4, 6, 6, 5].
UniqueList = gb_sets:to_list(gb_sets:from_list(List)).
% Alternatively the builtin:
Unique_list = lists:usort( List ).
Euphoria
include sort.e
function uniq(sequence s)
sequence out
s = sort(s)
out = s[1..1]
for i = 2 to length(s) do
if not equal(s[i],out[$]) then
out = append(out, s[i])
end if
end for
return out
end function
constant s = {1, 2, 1, 4, 5, 2, 15, 1, 3, 4}
? s
? uniq(s)
- Output:
{1,2,1,4,5,2,15,1,3,4} {1,2,3,4,5,15}
F#
The simplest way is to build a set from the given array (this actually works for any enumerable input sequence type, not just arrays):
set [|1;2;3;2;3;4|]
gives:
val it : Set<int> = seq [1; 2; 3; 4]
Factor
USING: sets ;
V{ 1 2 1 3 2 4 5 } members .
V{ 1 2 3 4 5 }
Forth
Forth has no built-in hashtable facility, so the easiest way to achieve this goal is to take the "uniq" program as an example.
The word uniq, if given a sorted array of cells, will remove the duplicate entries and return the new length of the array. For simplicity, uniq has been written to process cells (which are to Forth what "int" is to C), but could easily be modified to handle a variety of data types through deferred procedures, etc.
The input data is assumed to be sorted.
\ Increments a2 until it no longer points to the same value as a1
\ a3 is the address beyond the data a2 is traversing.
: skip-dups ( a1 a2 a3 -- a1 a2+n )
dup rot ?do
over @ i @ <> if drop i leave then
cell +loop ;
\ Compress an array of cells by removing adjacent duplicates
\ Returns the new count
: uniq ( a n -- n2 )
over >r \ Original addr to return stack
cells over + >r \ "to" addr now on return stack, available as r@
dup begin ( write read )
dup r@ <
while
2dup @ swap ! \ copy one cell
cell+ r@ skip-dups
cell 0 d+ \ increment write ptr only
repeat r> 2drop r> - cell / ;
Here is another implementation of "uniq" that uses a popular parameters and local variables extension words. It is structurally the same as the above implementation, but uses less overt stack manipulation.
: uniqv { a n \ r e -- n }
a n cells+ to e
a dup to r
\ the write address lives on the stack
begin
r e <
while
r @ over !
r cell+ e skip-dups to r
cell+
repeat
a - cell / ;
To test this code, you can execute:
create test 1 , 2 , 3 , 2 , 6 , 4 , 5 , 3 , 6 ,
here test - cell / constant ntest
: .test ( n -- ) 0 ?do test i cells + ? loop ;
test ntest 2dup cell-sort uniq .test
- Output:
1 2 3 4 5 6 ok
Fortran
Fortran has no built-in hash functions or sorting functions but the code below implements the compare all elements algorithm.
program remove_dups
implicit none
integer :: example(12) ! The input
integer :: res(size(example)) ! The output
integer :: k ! The number of unique elements
integer :: i, j
example = [1, 2, 3, 2, 2, 4, 5, 5, 4, 6, 6, 5]
k = 1
res(1) = example(1)
outer: do i=2,size(example)
do j=1,k
if (res(j) == example(i)) then
! Found a match so start looking again
cycle outer
end if
end do
! No match found so add it to the output
k = k + 1
res(k) = example(i)
end do outer
write(*,advance='no',fmt='(a,i0,a)') 'Unique list has ',k,' elements: '
write(*,*) res(1:k)
end program remove_dups
Same as above but using 'ANY' to check if the input number already exists in the array of unique elements:
program remove_dups
implicit none
integer :: example(12) ! The input
integer :: res(size(example)) ! The output
integer :: k ! The number of unique elements
integer :: i
example = [1, 2, 3, 2, 2, 4, 5, 5, 4, 6, 6, 5]
k = 1
res(1) = example(1)
do i=2,size(example)
! if the number already exist in res check next
if (any( res == example(i) )) cycle
! No match found so add it to the output
k = k + 1
res(k) = example(i)
end do
write(*,advance='no',fmt='(a,i0,a)') 'Unique list has ',k,' elements: '
write(*,*) res(1:k)
end program remove_dups
- Output:
Unique list has 6 elements: 1 2 3 4 5 6
Frink
The following demonstrates two of the simplest ways of removing duplicates.
b = [1, 5, 2, 6, 6, 2, 2, 1, 9, 8, 6, 5]
// One way, using OrderedList. An OrderedList is a type of array that keeps
// its elements in order. The items must be comparable.
a = new OrderedList
println[a.insertAllUnique[b]]
// Another way, using the "set" datatype and back to an array.
println[toArray[toSet[b]]
- Output:
Note that sets are not guaranteed to be printed in any specific order.
[1, 2, 5, 6, 8, 9] [9, 8, 6, 5, 2, 1]
GAP
# Built-in, using sets (which are also lists)
a := [ 1, 2, 3, 1, [ 4 ], 5, 5, [4], 6 ];
# [ 1, 2, 3, 1, [ 4 ], 5, 5, [ 4 ], 6 ]
b := Set(a);
# [ 1, 2, 3, 5, 6, [ 4 ] ]
IsSet(b);
# true
IsList(b);
# true
Go
Map solution
package main
import "fmt"
func uniq(list []int) []int {
unique_set := make(map[int]bool, len(list))
for _, x := range list {
unique_set[x] = true
}
result := make([]int, 0, len(unique_set))
for x := range unique_set {
result = append(result, x)
}
return result
}
func main() {
fmt.Println(uniq([]int{1, 2, 3, 2, 3, 4})) // prints: [3 4 1 2] (but in a semi-random order)
}
Map preserving order
It takes only small changes to the above code to preserver order. Just store the sequence in the map:
package main
import "fmt"
func uniq(list []int) []int {
unique_set := make(map[int]int, len(list))
i := 0
for _, x := range list {
if _, there := unique_set[x]; !there {
unique_set[x] = i
i++
}
}
result := make([]int, len(unique_set))
for x, i := range unique_set {
result[i] = x
}
return result
}
func main() {
fmt.Println(uniq([]int{1, 2, 3, 2, 3, 4})) // prints: [1 2 3 4]
}
Float64, removing duplicate NaNs
In solutions above, you just replace int
with another type to use for a list of another type. (See Associative_arrays/Creation#Go for acceptable types.) Except a weird thing happens with NaNs. They (correctly) don't compare equal, so you have to special case them if you want to remove duplicate NaNs:
package main
import (
"fmt"
"math"
)
func uniq(list []float64) []float64 {
unique_set := map[float64]int{}
i := 0
nan := false
for _, x := range list {
if _, exists := unique_set[x]; exists {
continue
}
if math.IsNaN(x) {
if nan {
continue
} else {
nan = true
}
}
unique_set[x] = i
i++
}
result := make([]float64, len(unique_set))
for x, i := range unique_set {
result[i] = x
}
return result
}
func main() {
fmt.Println(uniq([]float64{1, 2, math.NaN(), 2, math.NaN(), 4})) // Prints [1 2 NaN 4]
}
Any type using reflection
Go doesn't have templates or generics, but it does have reflection. Using this it's possible to build a version that will work on almost any array or slice type. Using the reflect package for this does make the code less readable.
Normally in Go this type of solution is somewhat rare. Instead, for very short code (such as min, max, abs) it's common to cast or make a type specific function by hand as needed. For longer code, often an interface can be used instead (see the sort
package for an example).
Note: due to details with how Go handles map keys that contain a NaN somewhere (including within a complex or even within a sub struct field) this version simply omits any NaN containing values it comes across and returns a bool to indicate if that happened. This version is otherwise a translation of the above order preserving map implementation, it does not for example call reflect.DeepEqual so elements with pointers to distinct but equal values will be treated as non-equal.
package main
import (
"fmt"
"math"
"reflect"
)
func uniq(x interface{}) (interface{}, bool) {
v := reflect.ValueOf(x)
if !v.IsValid() {
panic("uniq: invalid argument")
}
if k := v.Kind(); k != reflect.Array && k != reflect.Slice {
panic("uniq: argument must be an array or a slice")
}
elemType := v.Type().Elem()
intType := reflect.TypeOf(int(0))
mapType := reflect.MapOf(elemType, intType)
m := reflect.MakeMap(mapType)
i := 0
for j := 0; j < v.Len(); j++ {
x := v.Index(j)
if m.MapIndex(x).IsValid() {
continue
}
m.SetMapIndex(x, reflect.ValueOf(i))
if m.MapIndex(x).IsValid() {
i++
}
}
sliceType := reflect.SliceOf(elemType)
result := reflect.MakeSlice(sliceType, i, i)
hadNaN := false
for _, key := range m.MapKeys() {
ival := m.MapIndex(key)
if !ival.IsValid() {
hadNaN = true
} else {
result.Index(int(ival.Int())).Set(key)
}
}
return result.Interface(), hadNaN
}
type MyType struct {
name string
value float32
}
func main() {
intArray := [...]int{5, 1, 2, 3, 2, 3, 4}
intSlice := []int{5, 1, 2, 3, 2, 3, 4}
stringSlice := []string{"five", "one", "two", "three", "two", "three", "four"}
floats := []float64{1, 2, 2, 4,
math.NaN(), 2, math.NaN(),
math.Inf(1), math.Inf(1), math.Inf(-1), math.Inf(-1)}
complexes := []complex128{1, 1i, 1 + 1i, 1 + 1i,
complex(math.NaN(), 1), complex(1, math.NaN()),
complex(math.Inf(+1), 1), complex(1, math.Inf(1)),
complex(math.Inf(-1), 1), complex(1, math.Inf(1)),
}
structs := []MyType{
{"foo", 42},
{"foo", 2},
{"foo", 42},
{"bar", 42},
{"bar", 2},
{"fail", float32(math.NaN())},
}
fmt.Print("intArray: ", intArray, " → ")
fmt.Println(uniq(intArray))
fmt.Print("intSlice: ", intSlice, " → ")
fmt.Println(uniq(intSlice))
fmt.Print("stringSlice: ", stringSlice, " → ")
fmt.Println(uniq(stringSlice))
fmt.Print("floats: ", floats, " → ")
fmt.Println(uniq(floats))
fmt.Print("complexes: ", complexes, "\n → ")
fmt.Println(uniq(complexes))
fmt.Print("structs: ", structs, " → ")
fmt.Println(uniq(structs))
// Passing a non slice or array will compile put
// then produce a run time panic:
//a := 42
//uniq(a)
//uniq(nil)
}
- Output:
intArray: [5 1 2 3 2 3 4] → [5 1 2 3 4] false intSlice: [5 1 2 3 2 3 4] → [5 1 2 3 4] false stringSlice: [five one two three two three four] → [five one two three four] false floats: [1 2 2 4 NaN 2 NaN +Inf +Inf -Inf -Inf] → [1 2 4 +Inf -Inf] true complexes: [(1+0i) (0+1i) (1+1i) (1+1i) (NaN+1i) (1+NaNi) (+Inf+1i) (1+Infi) (-Inf+1i) (1+Infi)] → [(1+0i) (0+1i) (1+1i) (+Inf+1i) (1+Infi) (-Inf+1i)] true structs: [{foo 42} {foo 2} {foo 42} {bar 42} {bar 2} {fail NaN}] → [{foo 42} {foo 2} {bar 42} {bar 2}] true
Groovy
def list = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
assert list.size() == 12
println " Original List: ${list}"
// Filtering the List (non-mutating)
def list2 = list.unique(false)
assert list2.size() == 8
assert list.size() == 12
println " Filtered List: ${list2}"
// Filtering the List (in place)
list.unique()
assert list.size() == 8
println " Original List, filtered: ${list}"
def list3 = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
assert list3.size() == 12
// Converting to Set
def set = list as Set
assert set.size() == 8
println " Set: ${set}"
- Output:
Original List: [1, 2, 3, a, b, c, 2, 3, 4, b, c, d] Filtered List: [1, 2, 3, a, b, c, 4, d] Original List, filtered: [1, 2, 3, a, b, c, 4, d] Set: [1, 2, 3, a, b, c, 4, d]
Haskell
Usage
print $ unique [4, 5, 4, 2, 3, 3, 4]
[4,5,2,3]
Sorted result using Set
O(n ln(n)). Requires there is a partial ordering of elements.
import qualified Data.Set as Set
unique :: Ord a => [a] -> [a]
unique = Set.toList . Set.fromList
Unsorted result using Set
O(n ln(n)). Retains original order. Requires there is a partial ordering of elements.
import Data.Set
unique :: Ord a => [a] -> [a]
unique = loop empty
where
loop s [] = []
loop s (x : xs) | member x s = loop s xs
| otherwise = x : loop (insert x s) xs
Using filter
O(n^2). Retains original order. Only requires that elements can be compared for equality.
import Data.List
unique :: Eq a => [a] -> [a]
unique [] = []
unique (x : xs) = x : unique (filter (x /=) xs)
Standard Library
import Data.List
Data.List.nub :: Eq a => [a] -> [a]
Data.List.Unique.unique :: Ord a => [a] -> [a]
HicEst
REAL :: nums(12)
CHARACTER :: workspace*100
nums = (1, 3, 2, 9, 1, 2, 3, 8, 8, 1, 0, 2)
WRITE(Text=workspace) nums ! convert to string
EDIT(Text=workspace, SortDelDbls=workspace) ! do the job for a string
READ(Text=workspace, ItemS=individuals) nums ! convert to numeric
WRITE(ClipBoard) individuals, "individuals: ", nums ! 6 individuals: 0 1 2 3 8 9 0 0 0 0 0 0
Icon and Unicon
This solution preserves the original order of the elements.
A sample run is:
->noDups a b c d c a b e a b c d e ->
IDL
non_repeated_values = array[uniq(array, sort( array))]
Inform 7
To decide which list of Ks is (L - list of values of kind K) without duplicates:
let result be a list of Ks;
repeat with X running through L:
add X to result, if absent;
decide on result.
J
The verb ~.
removes duplicate items from any array (numeric, character, or other; vector, matrix, rank-n array). For example:
~. 4 3 2 8 0 1 9 5 1 7 6 3 9 9 4 2 1 5 3 2
4 3 2 8 0 1 9 5 7 6
~. 'chthonic eleemosynary paronomasiac'
chtoni elmsyarp
Or (since J defines an item of an n dimensional array as its n-1 dimensional sub arrays):
0 1 1 2 0 */0 1 2
0 0 0
0 1 2
0 1 2
0 2 4
0 0 0
~. 0 1 1 2 0 */0 1 2
0 0 0
0 1 2
0 2 4
Jakt
The array version preserves order based on first occurrence.
fn deduplicated<T>(anon array: [T]) throws -> [T] {
mut existing_items: {T} = {}
mut result: [T] = []
for value in array {
if not existing_items.contains(value) {
existing_items.add(value)
result.push(value)
}
}
return result
}
fn deduplicated_set<T>(anon array: [T]) throws -> {T} {
mut result: {T} = {}
for value in array {
result.add(value)
}
return result
}
fn main() {
let array = [1, 2, 3, 3, 2, 5, 4]
println("{}", deduplicated(array))
println("{}", deduplicated_set(array))
}
Java
There is more than 1 way to achieve this. The most logical approach will depend on your application.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
One way would be to add the values to a Set object, which only allows for unique values.
int[] removeDuplicates(int[] values) {
/* use a LinkedHashSet to preserve order */
Set<Integer> set = new LinkedHashSet<>();
for (int value : values)
set.add(value);
values = new int[set.size()];
Iterator<Integer> iterator = set.iterator();
int index = 0;
while (iterator.hasNext())
values[index++] = iterator.next();
return values;
}
Alternately, you could simply add the values to a mutable List, checking if the list already contains the value before adding it.
int[] removeDuplicates(int[] values) {
List<Integer> list = new ArrayList<>();
for (int value : values)
if (!list.contains(value)) list.add(value);
values = new int[list.size()];
int index = 0;
for (int value : list)
values[index++] = value;
return values;
}
[2, 1, 4, 1, 1, 3, 1, 3, 1, 4, 3, 2, 3, 4, 3, 2, 2, 3, 3, 3] [2, 1, 4, 3] [2, 4, 1, 4, 1, 4, 3, 1, 1, 3, 4, 4, 4, 4, 2, 1, 1, 2, 3, 2] [2, 4, 1, 3]
Alternate approaches
import java.util.*;
class Test {
public static void main(String[] args) {
Object[] data = {1, 1, 2, 2, 3, 3, 3, "a", "a", "b", "b", "c", "d"};
Set<Object> uniqueSet = new HashSet<Object>(Arrays.asList(data));
for (Object o : uniqueSet)
System.out.printf("%s ", o);
}
}
1 a 2 b 3 c d
import java.util.*;
class Test {
public static void main(String[] args) {
Object[] data = {1, 1, 2, 2, 3, 3, 3, "a", "a", "b", "b", "c", "d"};
Arrays.stream(data).distinct().forEach((o) -> System.out.printf("%s ", o));
}
}
1 2 3 a b c d
JavaScript
This uses the ===
"strict equality" operator, which does no type conversions (4 == "4"
is true but 4 === "4"
is false)
function unique(ary) {
// concat() with no args is a way to clone an array
var u = ary.concat().sort();
for (var i = 1; i < u.length; ) {
if (u[i-1] === u[i])
u.splice(i,1);
else
i++;
}
return u;
}
var ary = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d", "4"];
var uniq = unique(ary);
for (var i = 0; i < uniq.length; i++)
print(uniq[i] + "\t" + typeof(uniq[i]));
1 - number 2 - number 3 - number 4 - number 4 - string a - string b - string c - string d - string
Or, extend the prototype for Array:
Array.prototype.unique = function() {
var u = this.concat().sort();
for (var i = 1; i < u.length; ) {
if (u[i-1] === u[i])
u.splice(i,1);
else
i++;
}
return u;
}
var uniq = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"].unique();
With reduce and arrow functions (ES6):
Array.prototype.unique = function() {
return this.sort().reduce( (a,e) => e === a[a.length-1] ? a : (a.push(e), a), [] )
}
With sets and spread operator (ES6):
Array.prototype.unique = function() {
return [... new Set(this)]
}
If, however, the array is homogenous, or we wish to interpret it as such by using JavaScript's Abstract Equality comparison (as in '==', see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) then it proves significantly faster to use a hash table.
For example, in ES 5:
function uniq(lst) {
var u = [],
dct = {},
i = lst.length,
v;
while (i--) {
v = lst[i], dct[v] || (
dct[v] = u.push(v)
);
}
u.sort(); // optional
return u;
}
Or, to allow for customised definitions of equality and duplication, we can follow the Haskell prelude in defining a nub :: [a] -> [a] function which is a special case of nubBy :: (a -> a -> Bool) -> [a] -> [a]
(function () {
'use strict';
// nub :: [a] -> [a]
function nub(xs) {
// Eq :: a -> a -> Bool
function Eq(a, b) {
return a === b;
}
// nubBy :: (a -> a -> Bool) -> [a] -> [a]
function nubBy(fnEq, xs) {
var x = xs.length ? xs[0] : undefined;
return x !== undefined ? [x].concat(
nubBy(fnEq, xs.slice(1)
.filter(function (y) {
return !fnEq(x, y);
}))
) : [];
}
return nubBy(Eq, xs);
}
// TEST
return [
nub('4 3 2 8 0 1 9 5 1 7 6 3 9 9 4 2 1 5 3 2'.split(' '))
.map(function (x) {
return Number(x);
}),
nub('chthonic eleemosynary paronomasiac'.split(''))
.join('')
]
})();
- Output:
[[4, 3, 2, 8, 0, 1, 9, 5, 7, 6], "chtoni elmsyarp"]
Joy
DEFINE uniq == [[]] [[in] [swap pop] [cons] ifte] primrec.
jq
If it is acceptable to alter the ordering of elements, then the builtin (fast) filter, unique, can be used. It can be used for arrays with elements of any JSON type and returns the distinct elements in sorted order.
[4,3,2,1,1,2,3,4] | unique
If all but the first occurrence of each element should be deleted, then the following function could be used. It retains the advantage of imposing no restrictions on the types of elements in the array and for that reason is slightly more complex than would otherwise be required.
def removeAllButFirst:
# The hash table functions all expect the hash table to be the input.
# Is x in the hash table?
def hashed(x):
(x|tostring) as $value
| .[$value] as $bucket
| $bucket and (.[$value] | index([x]));
# Add x to the hash table:
def add_hash(x):
(x|tostring) as $value
| .[$value] as $bucket
| if $bucket and ($bucket | index([x])) then .
else .[$value] += [x]
end;
reduce .[] as $item
( [[], {}]; # [array, hash]
if .[1] | hashed($item) then .
else [ (.[0] + [$item]), (.[1] | add_hash($item)) ]
end)
| .[0];
Julia
a = [1, 2, 3, 4, 1, 2, 3, 4]
@show unique(a) Set(a)
- Output:
unique(a) = [1, 2, 3, 4] Set(a) = Set([4, 2, 3, 1])
K
(Inspired by the J version.)
a:4 5#20?13 / create a random 4 x 5 matrix
(12 7 12 4 3
6 3 7 4 7
3 8 3 1 2
2 12 6 4 1)
,/a / flatten to array
12 7 12 4 3 6 3 7 4 7 3 8 3 1 2 2 12 6 4 1
?,/a / distinct elements
12 7 4 3 6 8 1 2
?"chthonic eleemosynary paronomasiac"
"chtoni elmsyarp"
?("this";"that";"was";"that";"was";"this")
("this"
"that"
"was")
0 1 1 2 0 *\: 0 1 2
(0 0 0
0 1 2
0 1 2
0 2 4
0 0 0)
?0 1 1 2 0 *\: 0 1 2
(0 0 0
0 1 2
0 2 4)
Klingphix
( )
( "Now" "is" "the" "time" "for" "all" "good" "men" "to" "come" "to" "the" "aid" "of" "the" "party." )
len [
get rot over find
not (
[swap 0 put]
[nip]
) if
swap
] for
swap print drop nl
"End " input
- Output:
("Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "aid", "of", "party.") End
Kotlin
fun main(args: Array<String>) {
val data = listOf(1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d")
val set = data.distinct()
println(data)
println(set)
}
- Output:
[1, 2, 3, a, b, c, 2, 3, 4, b, c, d] [1, 2, 3, a, b, c, 4, d]
Lang5
: dip swap '_ set execute _ ;
: remove-duplicates
[] swap do unique? length 0 == if break then loop drop ;
: unique?
0 extract swap "2dup in if drop else append then" dip ;
[1 2 6 3 6 4 5 6] remove-duplicates .
Built-in function:
[1 2 6 3 6 4 5 6] 's distinct
[1 2 6 3 6 4 5 6] 's dress dup union .
Lasso
local(
x = array(3,4,8,1,8,1,4,5,6,8,9,6),
y = array
)
with n in #x where #y !>> #n do => { #y->insert(#n) }
// result: array(3, 4, 8, 1, 5, 6, 9)
Lambdatalk
{def removedup
{def removedup.loop
{lambda {:a :b}
{if {A.empty? :a}
then :b
else {removedup.loop {A.rest :a}
{if {= {A.in? {A.first :a} :b} -1}
then {A.addlast! {A.first :a} :b}
else :b}}}}}
{lambda {:s}
{S.replace (\[|\]|,) by space in
{A.disp
{removedup.loop {A.new :s} {A.new}}}}}}
-> removedup
{removedup 1 2 3 a b c 2 3 4 b c d}
-> 1 2 3 a b c 4 d
Logo
show remdup [1 2 3 a b c 2 3 4 b c d] ; [1 a 2 3 4 b c d]
Lua
items = {1,2,3,4,1,2,3,4,"bird","cat","dog","dog","bird"}
flags = {}
io.write('Unique items are:')
for i=1,#items do
if not flags[items[i]] then
io.write(' ' .. items[i])
flags[items[i]] = true
end
end
io.write('\n')
- Output:
Unique items are: 1 2 3 4 bird cat dog
Lua doesn't accept Not-a-Number (NaN) and nil as table key, we can handle them like this (Lua 5.3):
local items = {1,2,3,4,1,2,3,4,0/0,nil,"bird","cat","dog","dog","bird",0/0}
function rmdup(t)
local r,dup,c,NaN = {},{},1,{}
for i=1,#t do
local e = t[i]
local k = e~=e and NaN or e
if k~=nil and not dup[k] then
c, r[c], dup[k]= c+1, e, true
end
end
return r
end
print(table.concat(rmdup(items),' '))
- Output:
1 2 3 4 nan bird cat dog
M2000 Interpreter
Example of using a Stack object for two types, number (by default 1 is double type), and a list for fast search, append, delete. A stack object is a collection type, which we can use Push to add on top or use Data to append to bottom. A module call pass parameters to current stack, as a frame over, with the left item at the top of the stack.
Flush // current stack has no items
// Number pop a number from stack of values
// Letter pop a string from stack of values
Module TestList {
// current stack has a number, 101
// we can create a private stack
a=stack:=1, 1, "c", "d", 2, 2, 3, 3, 3, "a", "a", "b", "b"
// A list use key/values or key/Key as value. Keys can be number or strings
// Duplicate not allowed. Exist( list_type, key_to_exam) return true if key exist
// Lists are inventories types wich can't hold duplicates (error produce if append a duplicate)
// Lists have O(1) for insert, delete, search (using Hash Table)
b=list
stack a {
// replace current stack with a, old current stack kept
while not empty
if islet then // if is letter (string)
if not exist(b, stackitem$()) then Append b, letter$ else drop
else.if not exist(b, stackitem()) then
Append b, number
else
drop // drop the item
end if
end while
}
// now old current stack return as current stack
// we can sort the b list
Sort b
Print b // print the list, using right align on columns for numbers, left for strings.
Print Number=101 // true
}
TestList 101
Actual spaces on the result line are according to column width. Here is just one space.
- Output:
1 2 3a b c d
Maple
This is simplest with a list, which is an immutable array.
> L := [ 1, 2, 1, 2, 3, 3, 2, 1, "a", "b", "b", "a", "c", "b" ];
L := [1, 2, 1, 2, 3, 3, 2, 1, "a", "b", "b", "a", "c", "b"]
> [op]({op}(L));
[1, 2, 3, "a", "b", "c"]
That is idiomatic, but perhaps a bit cryptic; here is a more verbose equivalent:
> convert( convert( L, 'set' ), 'list' );
[1, 2, 3, "a", "b", "c"]
For an Array, which is mutable, the table solution works well in Maple.
> A := Array( L ):
> for u in A do T[u] := 1 end: Array( [indices]( T, 'nolist' ) );
[1, 2, 3, "c", "a", "b"]
Note that the output (due to the Array() constructor) is in fact an Array.
Mathematica/Wolfram Language
Built-in function:
DeleteDuplicates[{0, 2, 1, 4, 2, 0, 3, 1, 1, 1, 0, 3}]
gives back:
{0, 2, 1, 4, 3}
Delete duplicates and return sorted elements:
Union[{0, 2, 1, 4, 2, 0, 3, 1, 1, 1, 0, 3}]
- gives back
- :
{0, 1, 2, 3, 4}
MATLAB
MATLAB has a built-in function, "unique(list)", which performs this task.
Sample Usage:
>> unique([1 2 6 3 6 4 5 6])
ans =
1 2 3 4 5 6
NOTE: The unique function only works for vectors and not for true arrays.
Maxima
unique([8, 9, 5, 2, 0, 7, 0, 0, 4, 2, 7, 3, 9, 6, 6, 2, 4, 7, 9, 8, 3, 8, 0, 3, 7, 0, 2, 7, 6, 0]);
[0, 2, 3, 4, 5, 6, 7, 8, 9]
MAXScript
uniques = #(1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d")
for i in uniques.count to 1 by -1 do
(
id = findItem uniques uniques[i]
if (id != i) do deleteItem uniques i
)
MiniScript
items = [1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"]
d = {}
for i in items
d.push i
end for
print d.indexes
- Output:
["b", 1, "d", 3, "a", 4, "c", 2]
ML
mLite
A bit like option 3, except copying each element as encountered, and checking to see if it has already been encountered
fun mem (x, []) = false
| (x eql a, a :: as) = true
| (x, _ :: as) = mem (x, as)
;
fun remdup
([], uniq) = rev uniq
| (h :: t, uniq) = if mem(h, uniq) then
remdup (t, uniq)
else
remdup (t, h :: uniq)
| L = remdup (L, [])
;
println ` implode ` remdup ` explode "the quick brown fox jumped over the lazy dog";
println ` remdup [1,2,3,4,4,3,2,1, "dog","cat","dog", 1.1, 2.2, 3.3, 1.1];
- Output:
the quickbrownfxjmpdvlazyg [1, 2, 3, 4, dog, cat, 1.1, 2.2, 3.3]
Modula-2
MODULE RemoveDuplicates;
FROM STextIO IMPORT
WriteLn;
FROM SWholeIO IMPORT
WriteInt;
TYPE
TArrayRange = [1 .. 7];
TArray = ARRAY TArrayRange OF INTEGER;
VAR
DataArray, ResultArray: TArray;
ResultIndex, LastResultIndex, Position: CARDINAL;
IsNewNumber: BOOLEAN;
BEGIN
(* Set the data. *);
DataArray[1] := 1;
DataArray[2] := 2;
DataArray[3] := 2;
DataArray[4] := 3;
DataArray[5] := 4;
DataArray[6] := 5;
DataArray[7] := 5;
ResultArray[1] := DataArray[1];
LastResultIndex := 1;
Position := 1;
WHILE Position < HIGH(DataArray) DO
INC(Position);
IsNewNumber := TRUE;
ResultIndex := 1;
WHILE (ResultIndex <= LastResultIndex) AND IsNewNumber DO
IF DataArray[Position] = ResultArray[ResultIndex] THEN
IsNewNumber := FALSE;
END;
INC(ResultIndex);
END;
IF IsNewNumber THEN
INC(LastResultIndex);
ResultArray[LastResultIndex] := DataArray[Position];
END
END;
FOR ResultIndex := 1 TO LastResultIndex DO
WriteInt(ResultArray[ResultIndex], 1);
WriteLn;
END;
END RemoveDuplicates.
MUMPS
We'll take advantage of the fact that an array can only have one index of any specific value. Sorting into canonical order is a side effect. If the indices are strings containing the separator string, they'll be split apart.
REMDUPE(L,S)
;L is the input listing
;S is the separator between entries
;R is the list to be returned
NEW Z,I,R
FOR I=1:1:$LENGTH(L,S) SET Z($PIECE(L,S,I))=""
;Repack for return
SET I="",R=""
FOR SET I=$O(Z(I)) QUIT:I="" SET R=$SELECT($L(R)=0:I,1:R_S_I)
KILL Z,I
QUIT R
Example:
USER>W $$REMDUPE^ROSETTA("1,2,3,4,5,2,5,""HELLO"",42,""WORLD""",",") 1,2,3,4,5,42,"HELLO","WORLD"
Nanoquery
After executing, the list 'unique' will contain only the unique items.
items = {1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"}
unique = {}
for item in items
if not item in unique
unique.append(item)
end
end
Neko
/**
Remove duplicate elements, in Neko
*/
var original = $array(1, 2, 1, 4, 5, 2, 15, 1, 3, 4)
/* Create a table with only unique elements from the array */
var dedup = function(a) {
var size = $asize(a)
var hash = $hnew(size)
while size > 0 {
var v = a[size - 1]
var k = $hkey(v)
$hset(hash, k, v, null)
size -= 1
}
return hash
}
/* Show the original list and the unique values */
$print(original, "\n")
var show = function(k, v) $print(v, " ")
$hiter(dedup(original), show)
$print("\n")
- Output:
prompt$ nekoc remove-duplicates.neko prompt$ neko remove-duplicates.n [1,2,1,4,5,2,15,1,3,4] 1 2 3 4 5 15
Nemerle
using System.Console;
module RemDups
{
Main() : void
{
def nums = array[1, 4, 6, 3, 6, 2, 7, 2, 5, 2, 6, 8];
def unique = $[n | n in nums].RemoveDuplicates();
WriteLine(unique);
}
}
NetRexx
This sample takes advantage of the NetRexx built-in Rexx object's indexed string capability (associative arrays). Rexx indexed strings act very like hash tables:
/* NetRexx */
options replace format comments java crossref symbols nobinary
-- Note: Task requirement is to process "arrays". The following converts arrays into simple lists of words:
-- Putting the resulting list back into an array is left as an exercise for the reader.
a1 = [2, 3, 5, 7, 11, 13, 17, 19, 'cats', 222, -100.2, +11, 1.1, +7, '7.', 7, 5, 5, 3, 2, 0, 4.4, 2]
a2 = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
a3 = ['Now', 'is', 'the', 'time', 'for', 'all', 'good', 'men', 'to', 'come', 'to', 'the', 'aid', 'of', 'the', 'party.']
x = 0
lists = ''
x = x + 1; lists[0] = x; lists[x] = array2wordlist(a1)
x = x + 1; lists[0] = x; lists[x] = array2wordlist(a2)
x = x + 1; lists[0] = x; lists[x] = array2wordlist(a3)
loop ix = 1 to lists[0]
nodups_list = remove_dups(lists[ix])
say ix.right(4)':' lists[ix]
say ''.right(4)':' nodups_list
say
end ix
return
-- =============================================================================
method remove_dups(list) public static
newlist = ''
nodups = '0'
loop w_ = 1 to list.words()
ix = list.word(w_)
nodups[ix] = nodups[ix] + 1 -- we can even collect a count of dups if we want
end w_
loop k_ over nodups
newlist = newlist k_
end k_
return newlist.space
-- =============================================================================
method array2wordlist(ra = Rexx[]) public static
wordlist = ''
loop r_ over ra
wordlist = wordlist r_
end r_
return wordlist.space
- Output:
1: 2 3 5 7 11 13 17 19 cats 222 -100.2 11 1.1 7 7. 7 5 5 3 2 0 4.4 2 : 13 2 3 17 19 7. 4.4 5 222 7 -100.2 1.1 cats 0 11 2: 1 2 3 a b c 2 3 4 b c d : c 2 d 3 4 a b 1 3: Now is the time for all good men to come to the aid of the party. : Now aid for men to the party. come time of is all good
NewLISP
(unique '(1 2 3 a b c 2 3 4 b c d))
Nial
uniques := [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
cull uniques
=+-+-+-+-+-+-+-+-+
=|1|2|3|a|b|c|4|d|
=+-+-+-+-+-+-+-+-+
Using strand form
cull 1 1 2 2 3 3
=1 2 3
Nim
import sequtils, algorithm, intsets
# Go through the list, and for each element, check the rest of the list to see
# if it appears again,
var items = @[1, 2, 3, 2, 3, 4, 5, 6, 7]
echo deduplicate(items) # O(n^2)
proc filterDup(xs: openArray[int]): seq[int] =
result = @[xs[0]]
var last = xs[0]
for x in xs[1..xs.high]:
if x != last:
result.add(x)
last = x
# Put the elements into a hash table which does not allow duplicates.
var s = initIntSet()
for x in items:
s.incl(x)
echo s
# Sort the elements and remove consecutive duplicate elements.
sort(items, system.cmp[int]) # O(n log n)
echo filterDup(items) # O(n)
Oberon-2
MODULE RD;
IMPORT Out;
TYPE
TArray = ARRAY 7 OF INTEGER;
VAR
DataArray,ResultArray:TArray;
ResultIndex,LastResultIndex,Position:LONGINT;
IsNewNumber:BOOLEAN;
PROCEDURE Init(VAR A:TArray);
BEGIN
A[0] := 1; A[1] := 2; A[2] := 2; A[3] := 3;
A[4] := 4; A[5] := 5; A[6] := 5;
END Init;
BEGIN
Init(DataArray);
ResultArray[0] := DataArray[0];
LastResultIndex := 0;
Position := 0;
WHILE Position < LEN(DataArray)-1 DO
INC(Position);
IsNewNumber := TRUE;
ResultIndex := 0;
WHILE(ResultIndex <= LastResultIndex) & (IsNewNumber) DO
IF DataArray[Position] = ResultArray[ResultIndex] THEN
IsNewNumber := FALSE;
END;
INC(ResultIndex);
END;
IF IsNewNumber THEN
INC(LastResultIndex);
ResultArray[LastResultIndex] := DataArray[Position];
END;
END;
FOR ResultIndex := 0 TO LastResultIndex DO
Out.Int(ResultArray[ResultIndex],0); Out.Char(' ');
END;
Out.Ln;
END RD.
Objeck
use Structure;
bundle Default {
class Unique {
function : Main(args : String[]) ~ Nil {
nums := [1, 1, 2, 3, 4, 4];
unique := IntVector->New();
each(i : nums) {
n := nums[i];
if(unique->Has(n) = false) {
unique->AddBack(n);
};
};
each(i : unique) {
unique->Get(i)->PrintLine();
};
}
}
}
Objective-C
NSArray *items = [NSArray arrayWithObjects:@"A", @"B", @"C", @"B", @"A", nil];
NSSet *unique = [NSSet setWithArray:items];
OCaml
let uniq lst =
let unique_set = Hashtbl.create (List.length lst) in
List.iter (fun x -> Hashtbl.replace unique_set x ()) lst;
Hashtbl.fold (fun x () xs -> x :: xs) unique_set []
let _ =
uniq [1;2;3;2;3;4]
Another solution (preserves order of first occurrence):
let uniq lst =
let seen = Hashtbl.create (List.length lst) in
List.filter (fun x -> let tmp = not (Hashtbl.mem seen x) in
Hashtbl.replace seen x ();
tmp) lst
let _ =
uniq [1;2;3;2;3;4]
Solution reversing list order :
let uniq l =
let rec tail_uniq a l =
match l with
| [] -> a
| hd::tl -> tail_uniq (hd::a) (List.filter (fun x -> x != hd) tl) in
tail_uniq [] l
List.sort_uniq compare [1;2;3;2;3;4]
Octave
input=[1 2 6 4 2 32 5 5 4 3 3 5 1 2 32 4 4];
output=unique(input);
Oforth
The list is converted to a set to remove duplicate elements
- Output:
import: set [ 1, 2, 3, 1, 2, 4, 1, 3, 4, 5 ] asSet println [1, 2, 3, 4, 5]
ooRexx
data = .array~of(1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d")
uniqueData = .set~new~union(data)~makearray~sort
say "Unique elements are"
say
do item over uniqueData
say item
end
- Output:
Unique elements are 1 2 3 4 a b c d
Oz
The following solutions only works if the value type is allowed as a key in a dictionary.
declare
fun {Nub Xs}
D = {Dictionary.new}
in
for X in Xs do D.X := unit end
{Dictionary.keys D}
end
in
{Show {Nub [1 2 1 3 5 4 3 4 4]}}
PARI/GP
Sort and remove duplicates. Other methods should be implemented as well.
rd(v)={
vecsort(v,,8)
};
Pascal
Program RemoveDuplicates;
const
iArray: array[1..7] of integer = (1, 2, 2, 3, 4, 5, 5);
var
rArray: array[1..7] of integer;
i, pos, last: integer;
newNumber: boolean;
begin
rArray[1] := iArray[1];
last := 1;
pos := 1;
while pos < high(iArray) do
begin
inc(pos);
newNumber := true;
for i := low(rArray) to last do
if iArray[pos] = rArray[i] then
begin
newNumber := false;
break;
end;
if newNumber then
begin
inc(last);
rArray[last] := iArray[pos];
end;
end;
for i := low(rArray) to last do
writeln (rArray[i]);
end.
- Output:
% ./RemoveDuplicates 1 2 3 4 5
PascalABC.NET
begin
// By algorithm
var nums := Arr(1, 1, 2, 3, 4, 4);
var unique := new List<integer>;
foreach var x in nums do
if x not in unique then
unique.Add(x);
unique.Println;
// By method
var unique2 := nums.Distinct;
unique2.Println;
// Using hash set
var unique3 := HSet(nums);
unique3.Println;
end.
- Output:
1 2 3 4 1 2 3 4 1 2 3 4
Perl
(this version even preserves the order of first appearance of each element)
use List::MoreUtils qw(uniq);
my @uniq = uniq qw(1 2 3 a b c 2 3 4 b c d);
It is implemented like this:
my %seen;
my @uniq = grep {!$seen{$_}++} qw(1 2 3 a b c 2 3 4 b c d);
Note: the following two solutions convert elements to strings in the result, so if you give it references they will lose the ability to be dereferenced.
Alternately:
my %hash = map { $_ => 1 } qw(1 2 3 a b c 2 3 4 b c d);
my @uniq = keys %hash;
Alternately:
my %seen;
@seen{qw(1 2 3 a b c 2 3 4 b c d)} = ();
my @uniq = keys %seen;
Phix
Standard builtin. The "STABLE" option preserves order of first occurence. Applies to any data type. The default option for unique(), "SORT", obviously produces sorted output, and there is one other recognised option, "PRESORTED", which can be used either to avoid an unnecessary sort, or to only remove adjacent duplicates.
with javascript_semantics ?join(unique(split("Now is the time for all good men to come to the aid of the party."),"STABLE")) ?unique({1, 2, 1, 4, 5, 2, 15, 1, 3, 4},"STABLE") ?unique({1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"},"STABLE") ?unique({1,3,2,9,1,2,3,8,8,1,0,2},"STABLE") ?unique("chthonic eleemosynary paronomasiac","STABLE")
- Output:
"Now is the time for all good men to come aid of party." {1,2,4,5,15,3} {1,2,3,"a","b","c",4,"d"} {1,3,2,9,8,0} "chtoni elmsyarp"
Phixmonti
"Now" "is" "the" "time" "for" "all" "good" "men" "to" "come" "to" "the" "aid" "of" "the" "party." stklen tolist
0 tolist var newlist
len for
get newlist over find
not if
swap 0 put var newlist
else
drop drop
endif
endfor
newlist print drop
PHP
$list = array(1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd');
$unique_list = array_unique($list);
PicoLisp
There is a built-in function
(uniq (2 4 6 1 2 3 4 5 6 1 3 5))
- Output:
-> (2 4 6 1 3 5)
PL/I
*process mar(1,72);
remdup: Proc options(main);
declare t(20) fixed initial (6, 6, 1, 5, 6, 2, 1, 7,
5, 22, 4, 19, 1, 1, 6, 8, 9, 10, 11, 12);
declare (i, j, k, n, e) fixed;
put skip list ('Input:');
put edit ((t(k) do k = 1 to hbound(t))) (skip,20(f(3)));
n = hbound(t,1);
i = 0;
outer:
do k = 1 to n;
e = t(k);
do j = k-1 to 1 by -1;
if e = t(j) then iterate outer;
end;
i = i + 1;
t(i) = e;
end;
put skip list ('Unique elements are:');
put edit ((t(k) do k = 1 to i)) (skip,20(f(3)));
end;
- Output:
Input: 6 6 1 5 6 2 1 7 5 22 4 19 1 1 6 8 9 10 11 12 Unique elements are: 6 1 5 2 7 22 4 19 8 9 10 11 12
Pop11
;;; Initial array
lvars ar = {1 2 3 2 3 4};
;;; Create a hash table
lvars ht= newmapping([], 50, 0, true);
;;; Put all array as keys into the hash table
lvars i;
for i from 1 to length(ar) do
1 -> ht(ar(i))
endfor;
;;; Collect keys into a list
lvars ls = [];
appdata(ht, procedure(x); cons(front(x), ls) -> ls; endprocedure);
PostScript
[10 8 8 98 32 2 4 5 10 ] dup length dict begin aload let* currentdict {pop} map end
PowerShell
The common array for both approaches:
$data = 1,2,3,1,2,3,4,1
Using a hash table to remove duplicates:
$h = @{}
foreach ($x in $data) {
$h[$x] = 1
}
$h.Keys
Sorting and removing duplicates along the way can be done with the Sort-Object
cmdlet.
$data | Sort-Object -Unique
Removing duplicates without sorting can be done with the Select-Object
cmdlet.
$data | Select-Object -Unique
Prolog
uniq(Data,Uniques) :- sort(Data,Uniques).
Example usage:
?- uniq([1, 2, 3, 2, 3, 4],Xs).
Xs = [1, 2, 3, 4]
Because sort/2 is GNU prolog and not ISO here is an ISO compliant version:
member1(X,[H|_]) :- X==H,!.
member1(X,[_|T]) :- member1(X,T).
distinct([],[]).
distinct([H|T],C) :- member1(H,T),!, distinct(T,C).
distinct([H|T],[H|C]) :- distinct(T,C).
Example usage:
?- distinct([A, A, 1, 2, 3, 2, 3, 4],Xs).
Xs = [A, 1, 2, 3, 4]
Python
If all the elements are hashable (this excludes list, dict, set, and other mutable types), we can use a set:
items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
unique = list(set(items))
or if we want to keep the order of the elements
items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
unique = []
helperset = set()
for x in items:
if x not in helperset:
unique.append(x)
helperset.add(x)
If all the elements are comparable (i.e. <, >=, etc. operators; this works for list, dict, etc. but not for complex and many other types, including most user-defined types), we can sort and group:
import itertools
items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
unique = [k for k,g in itertools.groupby(sorted(items))]
If both of the above fails, we have to use the brute-force method, which is inefficient:
items = [1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']
unique = []
for x in items:
if x not in unique:
unique.append(x)
another way of removing duplicate elements from a list, while preserving the order would be to use OrderedDict module like so
from collections import OrderedDict as od
print(list(od.fromkeys([1, 2, 3, 'a', 'b', 'c', 2, 3, 4, 'b', 'c', 'd']).keys()))
See also http://www.peterbe.com/plog/uniqifiers-benchmark and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
We may also need to specify the particular type (or degree) of uniqueness and duplication that is at issue. Case-insensitive, with strings ? Unique with respect to a particular key in the case of dictionaries ?
One way to do this is to require an equality predicate, or perhaps a key function, in addition to a list to be pruned. For example, using itertools.groupby, at the cost of needing a sort and discarding order:
from itertools import (groupby)
# nubByKey :: (a -> b) -> [a] -> [a]
def nubByKey(k, xs):
return list(list(v)[0] for _, v in groupby(sorted(xs, key=k), key=k))
xs = [
'apple', 'apple',
'ampersand', 'aPPLE', 'Apple',
'orange', 'ORANGE', 'Orange', 'orange', 'apple'
]
for k in [
id, # default case sensitive uniqueness
lambda x: x.lower(), # case-insensitive uniqueness
lambda x: x[0], # unique first character (case-sensitive)
lambda x: x[0].lower(), # unique first character (case-insensitive)
]:
print (
nubByKey(k, xs)
)
- Output:
['apple', 'aPPLE', 'Apple', 'orange', 'ORANGE', 'Orange', 'ampersand'] ['ampersand', 'apple', 'orange'] ['Apple', 'ORANGE', 'apple', 'orange'] ['apple', 'orange']
Or alternatively, using an equality predicate with a recursive function which scales less well, but does preserve order:
# nubByEq :: (a -> a -> Bool) -> [a] -> [a]
def nubByEq(eq, xs):
def go(yys, xxs):
if yys:
y = yys[0]
ys = yys[1:]
return go(ys, xxs) if (
elemBy(eq, y, xxs)
) else (
[y] + go(ys, [y] + xxs)
)
else:
return []
return go(xs, [])
# elemBy :: (a -> a -> Bool) -> a -> [a] -> Bool
def elemBy(eq, x, xs):
if xs:
return eq(x, xs[0]) or elemBy(eq, x, xs[1:])
else:
return False
xs = [
'apple', 'apple',
'ampersand', 'aPPLE', 'Apple',
'orange', 'ORANGE', 'Orange', 'orange', 'apple'
]
for eq in [
lambda a, b: a == b, # default case sensitive uniqueness
lambda a, b: a.lower() == b.lower(), # case-insensitive uniqueness
lambda a, b: a[0] == b[0], # unique first char (case-sensitive)
lambda a, b: a[0].lower() == b[0].lower(), # unique first char (any case)
]:
print (
nubByEq(eq, xs)
)
A briefer definition of which might be in terms of filter:
# nubBy :: (a -> a -> Bool) -> [a] -> [a]
def nubBy(p, xs):
def go(xs):
if xs:
x = xs[0]
return [x] + go(
list(filter(
lambda y: not p(x, y),
xs[1:]
))
)
else:
return []
return go(xs)
- Output:
['apple', 'ampersand', 'aPPLE', 'Apple', 'orange', 'ORANGE', 'Orange'] ['apple', 'ampersand', 'orange'] ['apple', 'Apple', 'orange', 'ORANGE'] ['apple', 'orange']
Qi
(define remove-duplicates
[] -> []
[A|R] -> (remove-duplicates R) where (element? A R)
[A|R] -> [A|(remove-duplicates R)])
(remove-duplicates [a b a a b b c d e])
Quackery
uniquewith
sorts a nest and removes duplicate items from it.
The appropriate test for ordering two items is specified after uniquewith
,
so uniquewith >
would be appropriate for a nest of numbers, and return the nest
sorted in ascending numerical order, and uniquewith $<
would be appropriate for
a nest of strings sorted in descending order.
[ dup [] = iff ]else[ done
' sortwith nested
]'[ nested join do
behead dup dip nested rot
witheach
[ tuck != if
[ dup dip
[ nested join ] ] ]
drop ] is uniquewith ( [ --> [ )
' [ 1 2 3 5 6 7 8 1 2 3 4 5 6 7 ] uniquewith > echo
- Output:
[ 1 2 3 4 5 6 7 8 ]
R
items <- c(1,2,3,2,4,3,2)
unique (items)
Racket
Using the built-in function
-> (remove-duplicates '(2 1 3 2.0 a 4 5 b 4 3 a 7 1 3 x 2))
'(2 1 3 2.0 a 4 5 b 7 x)
Using a hash-table:
(define (unique/hash lst)
(hash-keys (for/hash ([x (in-list lst)]) (values x #t))))
Using a set:
(define unique/set (compose1 set->list list->set))
A definition that works with arbitrary sequences and allows specification of an equality predicate.
(define (unique seq #:same-test [same? equal?])
(for/fold ([res '()])
([x seq] #:unless (memf (curry same? x) res))
(cons x res)))
-> (unique '(2 1 3 2.0 a 4 5 b 4 3 a 7 1 3 x 2)) '(1 2 3 a b x 4 5 7 2.0) -> (unique '(2 1 3 2.0 4 5 4.0 3 7 1 3 2) #:same-test =) '(7 5 4 3 1 2) -> (unique #(2 1 3 2.0 4 5 4.0 3 7 1 3 2)) '(7 5 4 3 1 2) -> (apply string (unique "absbabsbdbfbd")) "fdsba"
Raku
(formerly Perl 6)
my @unique = [1, 2, 3, 5, 2, 4, 3, -3, 7, 5, 6].unique;
Or just make a set of it.
set(1,2,3,5,2,4,3,-3,7,5,6).list
Raven
[ 1 2 3 'a' 'b' 'c' 2 3 4 'b' 'c' 'd' ] as items
items copy unique print
list (8 items)
0 => 1
1 => 2
2 => 3
3 => "a"
4 => "b"
5 => "c"
6 => 4
7 => "d"
REBOL
print mold unique [1 $23.19 2 elbow 3 2 Bork 4 3 elbow 2 $23.19]
- Output:
[1 $23.19 2 elbow 3 Bork 4]
Red
>> items: [1 "a" "c" 1 3 4 5 "c" 3 4 5]
>> unique items
== [1 "a" "c" 3 4 5]
REXX
Note that in REXX, strings are quite literal.
- +7 is different from 7 (but compares numerically equal).
- 00 is different from 0 (but compares numerically equal).
- ─0 is different from 0 (but compares numerically equal).
- 7. is different from 7 (but compares numerically equal).
- Ab is different from AB (but can compare equal if made case insensitive).
Note that all the REXX examples below don't care what type of element is used, integer, floating point, character, binary, ···
version 1, using method 1
/*REXX program removes any duplicate elements (items) that are in a list (using a hash).*/
$= '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' /*item list.*/
say 'original list:' $
say right( words($), 17, '─') 'words in the original list.'
z=; @.= /*initialize the NEW list & index list.*/
do j=1 for words($); y= word($, j) /*process the words (items) in the list*/
if @.y=='' then z= z y; @.y= . /*Not duplicated? Add to Z list,@ array*/
end /*j*/
say
say 'modified list:' space(z) /*stick a fork in it, we're all done. */
say right( words(z), 17, '─') 'words in the modified list.'
- output when using the default input list:
original list: 2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 ──────────────23 words in the original list. modified list: 2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 0 4.4 ──────────────17 words in the modified list.
version 2, using a modified method 3
Instead of discard an element if it's a duplicated, it just doesn't add it to the new list.
Sorting of the list elements isn't necessary.
/*REXX program removes any duplicate elements (items) that are in a list (using a list).*/
$= '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2' /*item list.*/
say 'original list:' $
say right( words($), 17, '─') 'words in the original list.'
#= words($) /*process all the words in the list. */
do j=# by -1 for #; y= word($, j) /*get right-to-Left. */
_= wordpos(y, $, j + 1); if _\==0 then $= delword($, _, 1) /*Dup? Then delete it*/
end /*j*/
say
say 'modified list:' space($) /*stick a fork in it, we're all done. */
say right( words(z), 17, '─') 'words in the modified list.'
- output is identical to the 1st REXX version.
version 3, using method 3
/*REXX program removes any duplicate elements (items) that are in a list (using 2 lists)*/
old = '2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2'
say 'original list:' old
say right( words(old), 17, '─') 'words in the original list.'
new= /*start with a clean (list) slate. */
do j=1 for words(old); _= word(old, j) /*process the words in the OLD list. */
if wordpos(_, new)==0 then new= new _ /*Doesn't exist? Then add word to NEW.*/
end /*j*/
say
say 'modified list:' space(new) /*stick a fork in it, we're all done. */
say right( words(new), 17, '─') 'words in the modified list.'
- output is identical to the 1st REXX version.
version 4, using method 1 (hash table) via REXX stems
/* REXX ************************************************************
* 26.11.2012 Walter Pachl
* added: show multiple occurrences
**********************************************************************/
old='2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5',
'3 2 0 4.4 2'
say 'old list='old
say 'words in the old list=' words(old)
new=''
found.=0
count.=0
Do While old<>''
Parse Var old w old
If found.w=0 Then Do
new=new w
found.w=1
End
count.w=count.w+1
End
say 'new list='strip(new)
say 'words in the new list=' words(new)
Say 'Multiple occurrences:'
Say 'occ word'
Do While new<>''
Parse Var new w new
If count.w>1 Then
Say right(count.w,3) w
End
- Output:
old list=2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 7 5 5 3 2 0 4.4 2 words in the old list= 23 new list=2 3 5 7 11 13 17 19 cats 222 -100.2 +11 1.1 +7 7. 0 4.4 words in the new list= 17 Multiple occurrences: occ word 3 2 2 3 3 5 2 7
Ring
list = ["Now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "to", "the", "aid", "of", "the", "party."]
for i = 1 to len(list)
for j = i + 1 to len(list)
if list[i] = list[j] del(list, j) j-- ok
next
next
for n = 1 to len(list)
see list[n] + " "
next
see nl
Output:
Now is the time for all good men to come aid of party.
RPL
We follow here a fourth way, which requires few words and take advantage of the (relative) speed of the POS
function.
RPL code | Comment |
---|---|
≪ → input ≪ { } 1 input SIZE FOR j input j GET IF DUP2 POS THEN DROP ELSE + END NEXT ≫ ≫ ‘NODUP’ STO |
NODUP ( { a b a...c } -- { a b..c } ) Initialize output list Go through input list If input[j] already in output list then forget it else add it to output list End loop |
{ 1 2 3 'a' 'b' 'c' 2 3 4 'b' 'c' 'd' } NODUP
- Output:
1: { 1 2 3 'a' 'b' 'c' 4 'd' }
Ruby
Ruby has an Array#uniq
built-in method, which returns a new array by removing duplicate values in self.
ary = [1,1,2,1,'redundant',[1,2,3],[1,2,3],'redundant']
p ary.uniq # => [1, 2, "redundant", [1, 2, 3]]
You can also write your own uniq method.
class Array
# used Hash
def uniq1
each_with_object({}) {|elem, h| h[elem] = true}.keys
end
# sort (requires comparable)
def uniq2
sorted = sort
pre = sorted.first
sorted.each_with_object([pre]){|elem, uniq| uniq << (pre = elem) if elem != pre}
end
# go through the list
def uniq3
each_with_object([]) {|elem, uniq| uniq << elem unless uniq.include?(elem)}
end
end
ary = [1,1,2,1,'redundant',[1,2,3],[1,2,3],'redundant']
p ary.uniq1 #=> [1, 2, "redundant", [1, 2, 3]]
p ary.uniq2 rescue nil # Error (not comparable)
p ary.uniq3 #=> [1, 2, "redundant", [1, 2, 3]]
ary = [1,2,3,7,6,5,2,3,4,5,6,1,1,1]
p ary.uniq1 #=> [1, 2, 3, 7, 6, 5, 4]
p ary.uniq2 #=> [1, 2, 3, 4, 5, 6, 7]
p ary.uniq3 #=> [1, 2, 3, 7, 6, 5, 4]
A version without implementing class declarations:
def unique(array)
pure = Array.new
for i in array
flag = false
for j in pure
flag = true if j==i
end
pure << i unless flag
end
return pure
end
unique ["hi","hey","hello","hi","hey","heyo"] # => ["hi", "hey", "hello", "heyo"]
unique [1,2,3,4,1,2,3,5,1,2,3,4,5] # => [1,2,3,4,5]
Rust
use std::collections::HashSet;
use std::hash::Hash;
fn remove_duplicate_elements_hashing<T: Hash + Eq>(elements: &mut Vec<T>) {
let set: HashSet<_> = elements.drain(..).collect();
elements.extend(set.into_iter());
}
fn remove_duplicate_elements_sorting<T: Ord>(elements: &mut Vec<T>) {
elements.sort_unstable(); // order does not matter
elements.dedup();
}
fn main() {
let mut sample_elements = vec![0, 0, 1, 1, 2, 3, 2];
println!("Before removal of duplicates : {:?}", sample_elements);
remove_duplicate_elements_sorting(&mut sample_elements);
println!("After removal of duplicates : {:?}", sample_elements);
}
- Output:
Before removal of duplicates : [0, 0, 1, 1, 2, 3, 2] After removal of duplicates : [1, 0, 3, 2]
Scala
val list = List(1,2,3,4,2,3,4,99)
val l2 = list.distinct
// l2: scala.List[scala.Int] = List(1,2,3,4,99)
val arr = Array(1,2,3,4,2,3,4,99)
val arr2 = arr.distinct
// arr2: Array[Int] = Array(1, 2, 3, 4, 99)
Scheme
(define (remove-duplicates l)
(cond ((null? l)
'())
((member (car l) (cdr l))
(remove-duplicates (cdr l)))
(else
(cons (car l) (remove-duplicates (cdr l))))))
(remove-duplicates '(1 2 1 3 2 4 5))
(1 3 2 4 5)
Alternative approach:
(define (remove-duplicates l)
(do ((a '() (if (member (car l) a) a (cons (car l) a)))
(l l (cdr l)))
((null? l) (reverse a))))
(remove-duplicates '(1 2 1 3 2 4 5))
(1 2 3 4 5)
The function 'delete-duplicates' is also available in srfi-1.
Seed7
$ include "seed7_05.s7i";
const proc: main is func
local
const array integer: data is [] (1, 3, 2, 9, 1, 2, 3, 8, 8, 1, 0, 2);
var set of integer: dataSet is (set of integer).value;
var integer: number is 0;
begin
for number range data do
incl(dataSet, number);
end for;
writeln(dataSet);
end func;
- Output:
{0, 1, 2, 3, 8, 9}
SETL
items := [0,7,6,6,4,9,7,1,2,3,2];
print(unique(items));
Output in arbitrary order (convert tuple->set then set->tuple):
proc unique(items);
return [item: item in {item: item in items}];
end proc;
Preserving source order
proc unique(items);
seen := {};
return [item: item in items, nps in {#seen} | #(seen with:= item) > nps];
end proc;
proc unique(items);
seen := {};
return [item: item in items, nps in {#seen} | #(seen with:= item) > nps];
end proc;
items := [0,7,6,6,4,9,7,1,2,3,2];
print(unique(items));
Output in arbitrary order (convert tuple->set then set->tuple):
proc unique(items);
return [item: item in {item: item in items}];
end proc;
SETL4
set = new('set')
* Add all the elements of the array to the set.
add(set,array)
Sidef
var ary = [1,1,2,1,'redundant',[1,2,3],[1,2,3],'redundant'];
say ary.uniq.dump;
say ary.last_uniq.dump;
- Output:
[1, 2, 'redundant', [1, 2, 3]] [2, 1, [1, 2, 3], 'redundant']
Slate
[|:s| #(1 2 3 4 1 2 3 4) >> s] writingAs: Set.
"==> {"Set traitsWindow" 1. 2. 3. 4}"
Smalltalk
"Example of creating a collection"
|a|
a := #( 1 1 2 'hello' 'world' #symbol #another 2 'hello' #symbol ).
a asSet.
- Output:
Set (1 2 #symbol 'world' #another 'hello' )
the above has the disadvantage of loosing the original order (because Sets are unordered, and the hashing shuffles elements into an arbitrary order). When tried, I got:
Set('world' 1 #another 'hello' #symbol 2)
on my system. This can be avoided by using an ordered set (which has also O(n) complexity) as below:
|a|
a := #( 1 1 2 'hello' 'world' #symbol #another 2 'hello' #symbol ).
a asOrderedSet.
- Output:
OrderedSet(1 2 'hello' 'world' #symbol #another)
Sparkling
function undupe(arr) {
var t = {};
foreach(arr, function(key, val) {
t[val] = true;
});
var r = {};
foreach(t, function(key) {
r[sizeof r] = key;
});
return r;
}
SQL
This is not a particularly efficient solution, but it gets the job done.
/*
This code is an implementation of "Remove duplicate elements" in SQL ORACLE 19c
p_in_str -- input string
p_delimiter -- delimeter
*/
with
function remove_duplicate_elements(p_in_str in varchar2, p_delimiter in varchar2 default ',') return varchar2 is
v_in_str varchar2(32767) := replace(p_in_str,p_delimiter,',');
v_res varchar2(32767);
begin
--
execute immediate 'select listagg(distinct cv,:p_delimiter) from (select (column_value).getstringval() cv from xmltable(:v_in_str))'
into v_res using p_delimiter, v_in_str;
--
return v_res;
--
end;
--Test
select remove_duplicate_elements('1, 2, 3, "a", "b", "c", 2, 3, 4, "b", "c", "d"') as res from dual
union all
select remove_duplicate_elements('3 9 1 10 3 7 6 5 2 7 4 7 4 2 2 2 2 8 2 10 4 9 2 4 9 3 4 3 4 7',' ') as res from dual
;
- Output:
1,2,3,4,a,b,c,d 1 10 2 3 4 5 6 7 8 9
Stata
Duplicates in a dataset
Stata can report duplicate lines, or remove them. See duplicates in Stata help.
. clear all
. input x y
1 1
1 1
1 2
2 1
2 2
1 1
2 1
2 1
1 2
2 2
end
. duplicates drop x y, force
. list
+-------+
| x y |
|-------|
1. | 1 1 |
2. | 1 2 |
3. | 2 1 |
4. | 2 2 |
+-------+
Mata
The uniqrows function removes duplicate rows from a matrix.
. mata
: a=1,1\1,1\1,2\2,1\2,2\1,1\2,1\2,1\1,2\2,2
: a
1 2
+---------+
1 | 1 1 |
2 | 1 1 |
3 | 1 2 |
4 | 2 1 |
5 | 2 2 |
6 | 1 1 |
7 | 2 1 |
8 | 2 1 |
9 | 1 2 |
10 | 2 2 |
+---------+
: uniqrows(a)
1 2
+---------+
1 | 1 1 |
2 | 1 2 |
3 | 2 1 |
4 | 2 2 |
+---------+
Swift
Requires elements to be hashable:
println(Array(Set([3,2,1,2,3,4])))
- Output:
[2, 3, 1, 4]
Another solution (preserves order of first occurrence). Also requires elements to be hashable:
func uniq<T: Hashable>(lst: [T]) -> [T] {
var seen = Set<T>(minimumCapacity: lst.count)
return lst.filter { x in
let unseen = !seen.contains(x)
seen.insert(x)
return unseen
}
}
println(uniq([3,2,1,2,3,4]))
- Output:
[3, 2, 1, 4]
Only requires elements to be equatable, but runs in O(n^2):
func uniq<T: Equatable>(lst: [T]) -> [T] {
var seen = [T]()
return lst.filter { x in
let unseen = find(seen, x) == nil
if (unseen) {
seen.append(x)
}
return unseen
}
}
println(uniq([3,2,1,2,3,4]))
- Output:
[3, 2, 1, 4]
Tcl
The concept of an "array" in Tcl is strictly associative - and since there cannot be duplicate keys, there cannot be a redundant element in an array.
What is called "array" in many other languages is probably better represented by the "list" in Tcl (as in LISP).
With the correct option, the lsort
command will remove duplicates.
set result [lsort -unique $listname]
TSE SAL
//
// Go through the list, and for each element, check the rest of the list to see if it appears again, and discard it if it does.
//
INTEGER PROC FNBlockGetUniqueAllToBufferB( INTEGER bufferI )
INTEGER B = FALSE
INTEGER downB = TRUE
STRING s[255] = ""
IF ( NOT ( IsBlockInCurrFile() ) ) Warn( "Please mark a block" ) B = FALSE RETURN( B ) ENDIF // return from the current procedure if no block is marked
PushPosition()
PushBlock()
GotoBlockBegin()
WHILE ( ( IsCursorInBlock() ) AND ( downB ) )
s = GetText( 1, MAXSTRINGLEN )
PushPosition()
PushBlock()
GotoBufferId( bufferI )
IF NOT LFind( s, "" )
AddLine( s )
ENDIF
PopBlock()
PopPosition()
downB = Down()
ENDWHILE
PopPosition()
PopBlock()
B = TRUE
RETURN( B )
END
//
PROC Main()
INTEGER bufferI = 0
PushPosition()
bufferI = CreateTempBuffer()
PopPosition()
Message( FNBlockGetUniqueAllToBufferB( bufferI ) ) // gives e.g. TRUE
GotoBufferId( bufferI )
END
- Output:
Input This is a test1 This is a test2 This is a test2 This is a test2 This is a test2 This is a test2 This is a test3 This is a test3 This is a test3 This is a test3 This is a test3 This is a test4
Output This is a test1 This is a test2 This is a test3 This is a test4
TUSCRIPT
$$ MODE TUSCRIPT
list_old="b'A'A'5'1'2'3'2'3'4"
list_sort=MIXED_SORT (list_old)
list_new=REDUCE (list_sort)
PRINT list_old
PRINT list_new
- Output:
(sorted)
b'A'A'5'1'2'3'2'3'4 1'2'3'4'5'A'b
or
$$ MODE TUSCRIPT
list_old="b'A'A'5'1'2'3'2'3'4"
DICT list CREATE
LOOP l=list_old
DICT list LOOKUP l,num
IF (num==0) DICT list ADD l
ENDLOOP
DICT list unload list
list_new=JOIN (list)
PRINT list_old
PRINT list_new
- Output:
b'A'A'5'1'2'3'2'3'4 b'A'5'1'2'3'4
UnixPipes
Assuming a sequence is represented by lines in a file.
bash$ # original list
bash$ printf '6\n2\n3\n6\n4\n2\n'
6
2
3
6
4
2
bash$ # made uniq
bash$ printf '6\n2\n3\n6\n4\n2\n'|sort -n|uniq
2
3
4
6
bash$
or
bash$ # made uniq
bash$ printf '6\n2\n3\n6\n4\n2\n'|sort -nu
2
3
4
6
bash$
Ursala
The algorithm is to partition the list by equality and take one representative from each class, which can be done by letting the built in partition operator, |=, use its default comparison relation. This works on lists of any type including character strings but the comparison is based only on structural equivalence. It's up to the programmer to decide whether that's a relevant criterion for equivalence or else specify a better one.
#cast %s
example = |=hS& 'mississippi'
- Output:
'mspi'
Vedit macro language
The input "array" is an edit buffer where each line is one element.
Sort(0, File_Size) // sort the data
While(Replace("^(.*)\N\1$", "\1", REGEXP+BEGIN+NOERR)){} // remove duplicates
Vim Script
call filter(list, 'count(list, v:val) == 1')
Visual FoxPro
LOCAL i As Integer, n As Integer, lcOut As String
CLOSE DATABASES ALL
CLEAR
CREATE CURSOR nums (num I)
INDEX ON num TAG num COLLATE "Machine"
SET ORDER TO 0
n = 50
RAND(-1)
FOR i = 1 TO n
INSERT INTO nums VALUES (RanInt(1, 10))
ENDFOR
SELECT num, COUNT(num) As cnt FROM nums ;
GROUP BY num INTO CURSOR grouped
LIST OFF TO FILE grouped.txt NOCONSOLE
lcOut = ""
SCAN
lcOut = lcOut + TRANSFORM(num) + ","
ENDSCAN
lcOut = LEFT(lcOut, LEN(lcOut)-1)
? lcOut
FUNCTION RanInt(tnLow As Integer, tnHigh As Integer) As Integer
RETURN INT((tnHigh - tnLow + 1)*RAND() + tnLow)
ENDFUNC
- Output:
NUM COUNT 1 6 2 5 3 6 4 8 5 4 6 3 7 8 8 7 9 3 Unique Values: 1,2,3,4,5,6,7,8,9
V (Vlang)
const list = 'a,1,a,b,b,c,d,e,d,0,f,f,5,f,g,h,1,3,3'
fn main() {
println(unique(list))
}
fn unique(list string) []string {
mut new_list := []string{}
for word in list.split(',') {
if new_list.any(it == word.str()) == false {
new_list << word
}
}
new_list.sort()
return new_list
}
- Output:
['0', '1', '3', '5', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Wart
def (dedup l)
let exists (table)
collect+each x l
unless exists.x
yield x
exists.x <- 1
- Output:
dedup '(1 3 2 9 1 2 3 8 8 1 0 2) => (1 3 2 9 8 0)
Wortel
@uniq [1 2 3 2 1 2 3] ; returns [1 2 3]
Wren
import "./sort" for Sort
// Using a map - order of distinct items is undefined.
var removeDuplicates1 = Fn.new { |a|
if (a.count <= 1) return a
var m = {}
for (e in a) m[e] = true
return m.keys.toList
}
// Sort elements and remove consecutive duplicates.
var removeDuplicates2 = Fn.new { |a|
if (a.count <= 1) return a
Sort.insertion(a)
for (i in a.count-1..1) {
if (a[i] == a[i-1]) a.removeAt(i)
}
return a
}
// Iterate through list and for each element check if it occurs later in the list.
// If it does, discard it.
var removeDuplicates3 = Fn.new { |a|
if (a.count <= 1) return a
var i = 0
while (i < a.count-1) {
var j = i + 1
while(j < a.count) {
if (a[i] == a[j]) {
a.removeAt(j)
} else {
j = j + 1
}
}
i = i + 1
}
return a
}
var a = [1,2,3,4,1,2,3,5,1,2,3,4,5]
System.print("Original: %(a)")
System.print("Method 1: %(removeDuplicates1.call(a.toList))") // copy original each time
System.print("Method 2: %(removeDuplicates2.call(a.toList))")
System.print("Method 3: %(removeDuplicates3.call(a.toList))")
- Output:
Original: [1, 2, 3, 4, 1, 2, 3, 5, 1, 2, 3, 4, 5] Method 1: [2, 1, 3, 5, 4] Method 2: [1, 2, 3, 4, 5] Method 3: [1, 2, 3, 4, 5]
XBS
func RemoveDuplicates(Array){
set NewArray = [];
foreach(k,v as Array){
if (NewArray->includes(v)){
Array->splice(toint(k),1);
} else {
NewArray->push(v);
}
}
}
set Arr = ["Hello",1,2,"Hello",3,1];
log(Arr);
RemoveDuplicates(Arr);
log(Arr);
- Output:
Hello,1,2,Hello,3,1 Hello,1,2,3
XPL0
code Text=12; \built-in routine to display a string of characters
string 0; \use zero-terminated strings (not MSb terminated)
func StrLen(S); \Return number of characters in an ASCIIZ string
char S;
int I;
for I:= 0, -1>>1-1 do \(limit = 2,147,483,646 if 32 bit, or 32766 if 16 bit)
if S(I) = 0 then return I;
func Unique(S); \Remove duplicate bytes from string
char S;
int I, J, K, L;
[L:= StrLen(S); \string length
for I:= 0 to L-1 do \for all characters in string...
for J:= I+1 to L-1 do \scan rest of string for duplicates
if S(I) = S(J) then \if duplicate then
[for K:= J+1 to L do \ shift rest of string down (including
S(K-1):= S(K); \ terminating zero)
L:= L-1 \ string is now one character shorter
];
return S; \return pointer to string
];
Text(0, Unique("Pack my box with five dozen liquor jugs."))
- Output:
Pack myboxwithfvedznlqurjgs.
zkl
Using built ins:
zkl: Utils.Helpers.listUnique(T(1,3,2,9,1,2,3,8,8,"8",1,0,2,"8"))
L(1,3,2,9,8,"8",0)
zkl: "1,3,2,9,1,2,3,8,8,1,0,2".unique()
,012389
Where listUnique is brute force:
fcn listUnique(xs){
xs.reduce(fcn(us,s){us.holds(s) and us or us.append(s)},L()) }
Zoea
program: remove_duplicate_elements
input: [1,2,1,3,2,4,1]
output: [1,2,3,4]
Zoea Visual
- Programming Tasks
- Sorting Algorithms
- Sorting
- 11l
- 360 Assembly
- 8080 Assembly
- ACL2
- Action!
- Action! Tool Kit
- Ada
- Aime
- ALGOL 68
- Amazing Hopper
- APL
- AppleScript
- Arturo
- ATS
- AutoHotkey
- AWK
- BASIC
- ANSI BASIC
- Applesoft BASIC
- BASIC256
- BBC BASIC
- FreeBASIC
- FutureBasic
- Gambas
- GW-BASIC
- IS-BASIC
- Liberty BASIC
- Microsoft Small Basic
- PureBasic
- Run BASIC
- True BASIC
- VBA
- VBScript
- Yabasic
- BQN
- Bracmat
- Brat
- C
- C sharp
- C++
- CafeOBJ
- Ceylon
- Clojure
- CoffeeScript
- Common Lisp
- Crystal
- D
- Delphi
- Déjà Vu
- E
- EasyLang
- ECL
- Elena
- Ecstasy
- Elixir
- Erlang
- Euphoria
- F Sharp
- Factor
- Forth
- Fortran
- Frink
- GAP
- Go
- Groovy
- Haskell
- HicEst
- Icon
- Unicon
- IDL
- Inform 7
- J
- Jakt
- Java
- JavaScript
- Joy
- Jq
- Julia
- K
- Klingphix
- Kotlin
- Lang5
- Lasso
- Lambdatalk
- Logo
- Lua
- M2000 Interpreter
- Maple
- Mathematica
- Wolfram Language
- MATLAB
- Maxima
- MAXScript
- MiniScript
- ML
- MLite
- Modula-2
- MUMPS
- Nanoquery
- Neko
- Nemerle
- NetRexx
- NewLISP
- Nial
- Nim
- Oberon-2
- Objeck
- Objective-C
- OCaml
- Octave
- Oforth
- OoRexx
- Oz
- PARI/GP
- Pascal
- PascalABC.NET
- Perl
- Phix
- Phixmonti
- PHP
- PicoLisp
- PL/I
- Pop11
- PostScript
- Initlib
- PowerShell
- Prolog
- Python
- Qi
- Quackery
- R
- Racket
- Raku
- Raven
- REBOL
- Red
- REXX
- Ring
- RPL
- Ruby
- Rust
- Scala
- Scheme
- Seed7
- SETL
- SETL4
- Sidef
- Slate
- Smalltalk
- Sparkling
- SQL
- Stata
- Swift
- Tcl
- TSE SAL
- TUSCRIPT
- UnixPipes
- Ursala
- Vedit macro language
- Vim Script
- Visual FoxPro
- V (Vlang)
- Wart
- Wortel
- Wren
- Wren-sort
- XBS
- XPL0
- Zkl
- Zoea
- Zoea Visual
- Pages with too many expensive parser function calls