简体   繁体   English

为什么java.util.Set无法返回任何值?

[英]why java.util.Set can't return any value?

java.util.Set specifies only methods that return all records (via Iterator or array). java.util.Set仅指定返回所有记录(通过Iterator或数组)的方法。

Why is there no option to return any value from Set? 为什么没有选项可以从Set返回任何值?

It has a lot of sense in the real life. 在现实生活中有很多意义。 For example, I have a bowl of strawberries and I want to take just one of them. 例如,我有一碗草莓,我只想拿一个。 I totally don't care which one. 我完全不在乎哪个。

Why I can't do the same in java? 为什么我不能在Java中做同样的事情?

This is not answerable. 这是不负责任的。 You'd have to ask the original designers of the Java collections framework. 您必须询问Java Collections框架的原始设计者。

One plausible reason is that methods with non-deterministic behavior tend to be problematic: 一个可能的原因是具有不确定行为的方法往往会出现问题:

  • They make unit testing harder. 它们使单元测试更加困难。
  • They make bugs harder to track down. 它们使错误更难以追踪。
  • They are more easily misunderstood and misused by programmers who haven't bothered to read the API documentation. 他们更容易被不费心阅读API文档的程序员误解和滥用。

For hashtable-based set organizations, the behavior a "get some element" method is going to be non-deterministic, or at least difficult to determine / predict. 对于基于哈希表的集合组织,“获取某些元素”方法的行为将是不确定的,或者至少很难确定/预测。

By the way, you can trivially get some element of a non-empty set as follows: 顺便说一下,您可以像下面这样简单地获取非空集的某些元素:

Object someObject = someSet.iterator().next();

Getting a truly (pseudo-)random element is a bit more tricky / expensive because you can't index the elements of a set. 获取一个真正的(伪随机)元素会比较棘手/昂贵,因为您无法索引集合中的元素。 (You need to extract all of the set elements into an array ...) (您需要将所有设置的元素提取到数组中...)


On revisiting this, I realized that there is another reason. 回顾这一点,我意识到还有另一个原因。 It is simply that Set is based on the mathematical notion of a set, and the elements of a set in mathematics have no order. Set只是基于Set的数学概念,而数学中的集合元素没有顺序。 It is simply meaningless to talk about the first element of a mathematical set. 谈论数学集合的第一个元素根本没有意义。

A java.util.Set is an unordered collection; java.util.Set是无序集合; you can see it as a bag that contains things, but not in any particular order. 您可以将其视为装有物品的袋子,但没有任何特定的顺序。 It would not make sense to have a get(int index) method, because elements in a set don't have an index. 拥有get(int index)方法是没有意义的,因为集合中的元素没有索引。

The designers of the standard Java library didn't include a method to get a random element from a Set . 标准Java库的设计人员没有提供从Set获取随机元素的方法。 If you want to know why, that's something you can only speculate about. 如果您想知道为什么,那是您只能推测的事情。 Maybe they didn't think it was necessary, or maybe they didn't even think about it. 也许他们认为没有必要,或者甚至没有考虑。

It's easy to write a method yourself that gets a random element out of a Set . 自己编写一个从Set中获取随机元素的方法很容易。

If you don't care about the index of the elements, try using Queue instead of Set. 如果您不关心元素的索引,请尝试使用Queue而不是Set。

    Queue q = new ArrayDeque();
    q.element(); // retrieves the first object but doesn't remove
    q.poll(); // retrieves and removes first object

While a plain Set is in no particular, SortedSet and NavigableSet provide a guaranteed order and methods which support this. 虽然没有特别要求,但SortedSet和NavigableSet提供了保证顺序和支持此顺序的方法。 You can use first() and last() 您可以使用first()last()

SortedSet<E> set = ...
E e1 = set.first(); // a value
E e2 = set.last(); // also a value.

Actually the iterator is a lot better then using get(position) (which is something you can do on a java.util.List ). 实际上,迭代器比使用get(position)好得多(您可以在java.util.List )。 It allows for collection modifications during the iterations for one thing. 它允许在迭代过程中修改一件东西。 The reason you don't have them in sets is probably because most of them don't guarantee order of insertion. 您没有将它们放在集合中的原因可能是因为它们中的大多数不能保证插入顺序。 You can always do something like new ArrayList<?>(mySet).get(position) 您总是可以做类似new ArrayList<?>(mySet).get(position)

If you are not concerned with performance you can create a new type and back the data in an arraylist. 如果您不关心性能,则可以创建一个新类型并将其备份到arraylist中。

( Please note before donwvoting this is just an naive implementation of the idea and not the proposed final solution ) (请注意在放弃之前,这只是该想法的幼稚实现,而不是提议的最终解决方案)

import ...

public class PickableSet<E> extends AbstractSet<E>{

    private final List<E> arrayList = new ArrayList<E>();
    private final Set<E>  hashSet   = new HashSet<E>();
    private final Random  random    = new Random();

    public boolean add( E e ) {
        return hashSet.add( e ) && arrayList.add( e );
    }
    public int size() {
        return arrayList.size();
    }
    public Iterator<E> iterator() {
        return hashSet.iterator();
    }

    public E pickOne() {
        return arrayList.get( random.nextInt( arrayList.size() ) );
    }
}

Of course, since you're using a different interface you'll have to cast to invoke the method: 当然,由于您使用的是其他接口,因此必须强制转换以调用该方法:

Set<String> set = new PickableSet<String>();
set.add("one");
set.add("other");
String oneOfThem = ((PickableSet)set).pickOne();

ie https://gist.github.com/1986763 https://gist.github.com/1986763

Well, you can with a little bit of work like this 好吧,您可以像这样进行一些工作

    Set<String> s = new HashSet<String>();
    Random r = new Random();
    String res = s.toArray(new String[0])[r.nextInt(s.toArray().length)];

This grabs a randomly selected object from the set. 这将从集合中随机选择一个对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM