如何在Java中选择少量元素而不重复?

时间:2014-05-25 11:45:58

标签: java set repeat

一个例子: 我有一套

[a, b, c, d, e, f, g, h]

我想选择其中三个但不重复, 所以

[e, g, a] 

是正确的子集

[h, c, h]

不正确。

知道如何轻松清晰地制作它吗?

为了清楚起见: 我有一组测验的问题。它不是生成一个字母子集。 我想要的是: String数组的子集或数组的索引子集,例如从0到10。 因为它是一个测验,所以元素不能重复。

4 个答案:

答案 0 :(得分:1)

如果O(n)适合您,您可以遍历这些项目。对于每个项目,您可以随机选择它。

Set<Character> newSet = ...;

for (Char elem : set) {
   if (randomFunction()) {
      newSet.add(elem);
   }
}

答案 1 :(得分:1)

如果不考虑额外的内存使用情况,您可以在Collections.shuffle()上尝试使用List并获取前三个值。

Set<Character> set = new TreeSet<Character>();
for (char c = 'a'; c < 'i'; c++) {
    set.add(c);
}

List<Character> list = new ArrayList<Character>(set);
Collections.shuffle(list);
System.out.println(list.subList(0, 3));

你也可以试试这个

Random random = new Random();
int index = 0;

List<Character> list = new ArrayList<Character>(set);
Set<Character> newSet = new HashSet<Character>();
while (newSet.size() < 3) {
    index = random.nextInt(set.size());
    newSet.add(list.get(index));
}

答案 2 :(得分:0)

如果这是针对学校的,您可能需要避免使用方便的方法。这是一个简单的方法:

    ArrayList<String> al = new ArrayList<String>();
    al.add("a");
    al.add("b");
    al.add("c");
    al.add("d");
    al.add("e");
    al.add("f");
    al.add("g");
    al.add("h");

    int chooseNum = 3;
    Random rand = new Random();
    int index;
    String val;
    while (chooseNum > 0 && chooseNum <= al.size()) {
        index = rand.nextInt(al.size());
        val = al.remove(index);
        System.out.print(val);
        System.out.print(" ");
        chooseNum--;
    }

答案 3 :(得分:0)

我认为Braj的答案是最优雅的,但如果性能对您很重要,可以选择以下几种方式:

部分随机播放

这就像Braj的回答。除了它是O(k)而不是O(n)(其中k是拾取的元素的数量,n是输入的大小)。

/**
 * Randomly picks elements from a set.
 *
 * @param k Number of elements to choose.
 * @return A list containg k elements from the set.
 */
public Set<T> randomPick(int k) {
    T[] a = (T[]) new Object[k];
    a = this.inputSet.toArray(a);

    int n = a.length;

    if (k < 0 || k > n) {
        String msg = String.format(
                "Cannot pick %0 elements from a set that contains %1 elements.",
                k, n);
        throw new IllegalArgumentException(msg);
    }

    Random random = new Random();

    for (int i = 0; i < k; i++) {
        // Swap a[i] with a random element in the unswapped elements
        int r = i + random.nextInt(n - i);
        T temp = a[i];
        a[i] = a[r];
        a[r] = temp;
    }
    T[] output = Arrays.copyOfRange(a, 0, k);
    return new HashSet<T>(Arrays.asList(output));
}

尝试再次选择,直到拾取的元素数量符合预期

这非常简单。

我认为如果k很小则会更快,而当k接近n时效率会降低。

/**
 * Randomly picks elements from a set.
 *
 * @param k Number of elements to choose.
 * @return A list containg k elements from the set.
 */
public Set<T> randomPick2(int k) {
    List<T> list = new ArrayList<T>(this.inputSet);
    int n = list.size();

    if (k < 0 || k > n) {
        String msg = String.format(
                "Cannot pick %0 elements from a set that contains %1 elements.",
                k, n);
        throw new IllegalArgumentException(msg);
    }
    T[] a = (T[]) new Object[k];
    a = this.inputSet.toArray(a);

    Random random = new Random();

    Set<T> output = new HashSet<T>(k);
    while (output.size() < k) {
        int r = random.nextInt(n);
        output.add(a[r]);
    }
    return output;
}