Getting an arbitrary element from a set
In many algorithm, you're supposed to iterate over a set of elements, while the set is not empty.
Since you might change the set while iterating it, you typically pull an element out of the set, and then do the iteration, possibly adding or removing elements to or from the set. Here is a typical Java code to do that.
Set<Integer> possibleFactors = Sets.newHashSet(2,3,4,5,6,7,8,100);
while (!possibleFactors.isEmpty()) {
int factor = possibleFactors.iterator().next();
for (int i=1;i<10;i++) possibleFactors.remove(i*factor);
}
edit: As asked in the comments, I'll give a better example. I'm iterating through files the user have chosen, and I'm filtering them by checking the permissions of each item. However, as an optimization, if the user don't have permission for a certain directory, I'll remove all the files in it from the set.
Set<Path> input = Sets.newHashSet(userSelectedPaths);
while (!input.isEmpty()) {
Path path = input.iterator.next();
input.remove(path);
if (!expensivePermissionCheck(path)) {
input.removeAll(path.getFiles());
} else {
processPath(path);
}
}
However the first line in the loop looks weird. It c开发者_运维百科reates a superfluous Iterable
objects, when all I want is an arbitrary element from the set, I don't care in which order.
Except the performance, it looks kind of weird, and less readable.
Is there a better alternative? Maybe a different structure altogether?
edit: maybe a better formulation would be "How do I pop arbitrary element from a set?"
The only access methods for the Set
interface are via the iterator()
method or the toArray()
method.
If you have a SortedSet
you can use first()
or last()
method to access one item directly.
Actually it's not only not readable but it will also throw an exception if the set is empty.
Before getting the next()
you should always check hasNext()
then act based on that.
In a set there is no particular ordering of elements. You can remove or check the presence of element by providing its value (Set.remove(Object o) or Set.contains(Object o). You may consider to remove all elements from a set, or to paraphrase it keeping elements in set A that are not in set B by using
Set.removeAll(Set B);
For example
Set<Integer> A = new HashSet();
Set<Integer> B = new HashSet();
add numbers from 1-to-10 into A
add even numbers in range [1, 10] to B
A.removeAll(B);
println(A)
will print all odd numbers, eg those that are in A but not in B.
Alternatively you can call remove() method which removes element from a set if it exists :
for (int i = 2; i <= 10; i += 2) {
a.remove(i)
}
It will have same effect as removeAll() in above example.
Generally, a Set data structure is suitable when you work with collections of unique things and their ordering does not matter. Sets are useful (and fast) if you want to perform Union, Intersection, Diff etc operations on sets. If you have items that may be repeated more that once then you may consider using Multisets (google collections) if you care about ordering of things then Lists will be more helpful (but with worse performance though).
精彩评论