Union
Usage Message: Union[list1, list2, ... ] gives a sorted list of all the distinct elements that appear in any of
the listi. Union[list] gives a sorted version of a list, in which all duplicated elements have been dropped. Attributes[Union] = {Flat, OneIdentity, Protected} Options: SameTest
-> Automatic
Notes: The default test that is used in Union for identifying duplicated elements is equivalent to the test
that is used in Order
. This test is more strict than comparison using Equal
or SameQ
, so elements may not be dropped by Union even when comparison using Equal
or SameQ
returns True
. You can use the SameTest
option if you want to give a comparison test other than the default. Union sorts the elements before doing any comparisons, and treats
elements as duplicates only if they appear in adjacent positions after sorting. Restricting the comparisons to adjacent elements allows the Union
function to evaluate much more quickly (requiring time proportional to nlog(n) for a list of n elements) than
if it compared all pairs of elements (which requires time proportional to n^2). This design does not affect the result using the default
value of the SameTest
option, but it can affect the result if the test specified by the SameTest
option gives True
for elements that are not sorted into adjacent positions. (See below for examples of Union-like functions that compare all pairs of
elements.) Although the default comparison test in Union is equivalent to the test used by Order
, the Order
function is not called directly by Union, so changes to the definition of Order
function will not affect the behavior of Union. Various extensions to the current design of Union are being considered for future versions of Mathematica, including extensions to control sorting and way that comparisons are done. It is relatively easy to implement alternate designs of Union. Here is an example of a function which compares all pairs of elements.
In[1]:= union1[p_List, test_] := Module[{result, link},
result = link[];
Scan[Module[{r=result},
While[If[r===link[], result = link[result, #]; False,
!test[Last[r], #]], r = First[r]]] &, p];
List @@ Flatten[result, Infinity, link]
]
This function can be used in conjunction with a test that compares the first part of each element.
In[2]:= data = {f[1], g[1], h[2], f[2], h[3], g[2]} ;
In[3]:= test = Function[{x, y}, x[[1]] === y[[1]]] ;
In[4]:= union1[data, test]
Out[4]= {f[1], h[2], h[3]}
It is worth noting that the result using this type of comparison may depend on the order of the elements in the input.
In[5]:= union1[Reverse[data], test]
Out[5]= {g[2], h[3], g[1]}
The Union function gives a different result, since elements that are similar according to this test will not necessarily be sorted into adjacent positions.
In[6]:= Union[data, SameTest -> test]
Out[6]= {f[1], f[2], g[1], g[2], h[3]}
There are many other ways to write such a function. Here is one alternative.
In[7]:= union2[p_List, test_] := Module[{result, ei},
result = {};
Do[Catch[
ei = p[[i]];
Do[If[test[ei, result[[j]]],
Throw[Null]], {j, Length[result]}];
AppendTo[result, ei]],
{i, Length[p]}
];
result
]
In[8]:= union2[data, test]
Out[8]= {f[1], h[2], h[3]}
For larger lists, both of these functions will on average require time proportional to the square of the number of elements. It is possible with many comparison tests, including the test in this example, to take advantage of sorting to write a much faster function. The disadvantage of this method is that a different sorting function is required for each comparison test.
In[9]:= union3[p_List] := Module[{result, link},
sp = Sort[p, Function[{x, y}, x[[1]] < = y[[1]]]];
result = If[Length[sp] > 0, link[First[sp]], link[]];
Do[If[sp[[i-1, 1]] =!= sp[[i, 1]],
result = link[result, sp[[i]]]], {i, 2, Length[sp]}];
List @@ Flatten[result, Infinity, link]
]
In[10]:= union3[data]
Out[10]= {f[1], h[2], h[3]}
For larger lists, the method used in this last function is recommended, as it is considerably faster than methods that compare every pair of elements.
Additional Online Documentation:
Mathematica 3.0
http://documents.wolfram.com/v3/RefGuide/Union.html
Mathematica 4.0
http://documents.wolfram.com/v4/RefGuide/Union.html
Questions or comments? Send email to support@wolfram.com.
| |