User Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cl:functions:remove-duplicates [2019/09/14 05:00]
cl:functions:remove-duplicates [2019/09/20 08:00] (current)
Line 1: Line 1:
 +====== Function REMOVE-DUPLICATES,​ DELETE-DUPLICATES ======
 +
 +====Syntax====
 +  * **remove-duplicates** //​sequence//​ ''&​key''​ //​from-end//​ //test// //​test-not//​ //start// //end// //key// → //​result-sequence//​
 +  * **delete-duplicates** //​sequence//​ ''&​key''​ //​from-end//​ //test// //​test-not//​ //start// //end// //key// → //​result-sequence//​
 +
 +====Arguments and Values====
 +//​sequence//​ - a //​[[CL:​Glossary:​proper sequence]]//​.
 +//​from-end//​ - a //​[[CL:​Glossary:​generalized boolean]]//​. The default is //​[[CL:​Glossary:​false]]//​.
 +//test// - a //​[[CL:​Glossary:​designator]]//​ for a //​[[CL:​Glossary:​function]]//​ of two //​[[CL:​Glossary:​argument|arguments]]//​ that returns a //​[[CL:​Glossary:​generalized boolean]]//​.
 +//​test-not//​ - a //​[[CL:​Glossary:​designator]]//​ for a //​[[CL:​Glossary:​function]]//​ of two //​[[CL:​Glossary:​argument|arguments]]//​ that returns a //​[[CL:​Glossary:​generalized boolean]]//​.
 +//start//, //end// - //​[[CL:​Glossary:​bounding index designator|bounding index designators]]//​ of //​sequence//​. The defaults for //start// and //end// are ''​0''​ and **[[CL:​Constant Variables:​nil]]**,​ respectively.
 +//key// - a //​[[CL:​Glossary:​designator]]//​ for a //​[[CL:​Glossary:​function]]//​ of one argument, or **[[CL:​Constant Variables:​nil]]**.
 +//​result-sequence//​ - a //​[[CL:​Glossary:​sequence]]//​.
 +
 +====Description====
 +**remove-duplicates** returns a modified copy of //​sequence//​ from which any element that matches another element occurring in //​sequence//​ has been removed.
 +
 +If //​sequence//​ is a //​[[CL:​Glossary:​vector]]//,​ the result is a //​[[CL:​Glossary:​vector]]//​ that has the same //​[[CL:​Glossary:​actual array element type]]// as //​sequence//​.
 +
 +If //​sequence//​ is a //​[[CL:​Glossary:​list]]//,​ the result is a //​[[CL:​Glossary:​list]]//​.
 +
 +**delete-duplicates** is like **remove-duplicates**,​ but **delete-duplicates** may modify //​sequence//​.
 +
 +The elements of //​sequence//​ are compared //​[[CL:​Glossary:​pairwise]]//,​ and if any two match, then the one occurring earlier in //​sequence//​ is discarded, unless //​from-end//​ is //​[[CL:​Glossary:​true]]//,​ in which case the one later in //​sequence//​ is discarded.
 +
 +**remove-duplicates** and **delete-duplicates** return a //​[[CL:​Glossary:​sequence]]//​ of the same //​[[CL:​Glossary:​type]]//​ as //​sequence//​ with enough elements removed so that no two of the remaining elements match. The order of the elements remaining in the result is the same as the order in which they appear in //​sequence//​.
 +
 +**remove-duplicates** returns a //​[[CL:​Glossary:​sequence]]//​ that may share with //​sequence//​ or may be //​[[CL:​Glossary:​identical]]//​ to //​sequence//​ if no elements need to be removed.
 +
 +**delete-duplicates**,​ when //​sequence//​ is a //​[[CL:​Glossary:​list]]//,​ is permitted to **[[CL:​Macros:​setf]]** any part, **[[CL:​Functions:​car]]** or **[[CL:​Functions:​cdr]]**,​ of the top-level list structure in that //​sequence//​. When //​sequence//​ is a //​[[CL:​Glossary:​vector]]//,​ **delete-duplicates** is permitted to change the dimensions of the //​[[CL:​Glossary:​vector]]//​ and to slide its elements into new positions without permuting them to produce the resulting //​[[CL:​Glossary:​vector]]//​.
 +
 +====Examples====
 +<​blockquote>​
 +(remove-duplicates "​aBcDAbCd"​ :test #'​[[CL:​Functions:​char-equal]] :from-end [[CL:​Constant Variables:​t]]) <​r>"​aBcD"</​r>​
 +(remove-duplicates '(a b c b d d e)) <r>(A C B D E)</​r>​
 +(remove-duplicates '(a b c b d d e) :from-end [[CL:​Constant Variables:​t]]) <r>(A B C D E)</​r>​
 +(remove-duplicates '((foo #\a) (bar #\%) (baz #\A))
 +                   :test #'​[[CL:​Functions:​char-equal]] ​
 +                   :key #'​[[CL:​Functions:​cadr]]) <​r>​((BAR #\%) (BAZ #​\A))</​r>​
 +(remove-duplicates '((foo #\a) (bar #\%) (baz #\A)) 
 +                   :test #'​[[CL:​Functions:​char-equal]]
 +                   :key #'​[[CL:​Functions:​cadr]] :from-end [[CL:​Constant Variables:​t]]) ​ <​r>​((FOO #\a) (BAR #​\%))</​r>​
 +([[CL:​Constant Variables:​defparameter]] *tester* ([[CL:​Functions:​list]] 0 1 2 3 4 5 6)) <​r>​*TESTER*</​r>​
 +(delete-duplicates *tester* :key #'​[[CL:​Functions:​oddp]] :start 1 :end 6) <r>(0 4 5 6)</​r>​
 +</​blockquote>​
 +
 +====Side Effects====
 +**delete-duplicates** might destructively modify //​sequence//​.
 +
 +====Affected By====
 +None.
 +
 +====Exceptional Situations====
 +Should signal an error of type type-error if //​sequence//​ is not a //​[[CL:​Glossary:​proper sequence]]//​.
 +
 +====See Also====
 +  * {\secref\ConstantModification}
 +  * {\secref\TraversalRules}
 +
 +====Notes====
 +If //​sequence//​ is a //​[[CL:​Glossary:​vector]]//,​ the result might or might not be simple, and might or might not be //​[[CL:​Glossary:​identical]]//​ to //​sequence//​.
 +
 +The **'':​test-not''​** //​[[CL:​Glossary:​argument]]//​ is deprecated.
 +
 +These functions are useful for converting //​sequence//​ into a canonical form suitable for representing a set.
 +
 +\issue{SUBSEQ-OUT-OF-BOUNDS} \issue{RANGE-OF-START-AND-END-PARAMETERS:​INTEGER-AND-INTEGER-NIL} \issue{REMF-DESTRUCTION-UNSPECIFIED:​X3J13-MAR-89} \issue{CONSTANT-MODIFICATION:​DISALLOW} \issue{MAPPING-DESTRUCTIVE-INTERACTION:​EXPLICITLY-VAGUE} \issue{TEST-NOT-IF-NOT:​FLUSH-ALL}