【问题标题】:How to add an integer to a set while iterating?迭代时如何将整数添加到集合中?
【发布时间】:2017-08-02 21:37:13
【问题描述】:

我有一组整数:Set<Set<Integer>>。 我需要将整数添加到集合中,就好像它是一个双数组一样。所以 add(2,3) 必须将整数 3 添加到第二组。 我知道一套不太适合这个手术,但这不是我的决定。 下面的注释行显然不起作用,但它表明了意图。

我的问题是如何在迭代时将整数添加到集合中? 如果需要识别每一组,如何做到这一点?

@Override
public void add(int a, int b) {
    if (!isValidPair(a, b)) {
        throw new IllegalStateException("!isValidPair does not hold for (a,b)");
    }

    Iterator<Set<Integer>> it = relation.iterator();
    int i = 0;

    while (it.hasNext() && i <= a) {
        //it.next().add(b);
          i++;
    }
}

【问题讨论】:

  • “下面的注释行显然不起作用” - 请详细说明。
  • 我同意:在谈论条目的“顺序”时,集合不是合适的数据结构。而且“不起作用”并不是对在寻求帮助时会起作用的问题的描述。
  • Appologies,注释行给出了 java.util.NoSuchElementException(但确实可以编译)。

标签: java iterator set


【解决方案1】:

您应该注意的一个基本事项,这使得该问题中的所有现有答案都不起作用:

一旦在Set 中添加了一个对象(类似地,作为Map 中的键),它就不应更改(至少不会在会更改其equals()hashCode() 的方面)。仅当您将对象添加到Set 中时才会进行“唯一性”检查。

例如

Set<Set<Integer>> bigSet = new HashSet<>();
Set<Integer> v1 = new HashSet<>(Arrays.asList(1,2));
bigSet.add(v1);

System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2))));  // True

v1.add(3);

System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2))));    // False!!
System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2,3))));  // False!!

您可以看到该集合是如何损坏的。它包含一个[1,2,3],但contains() 不起作用,既不适用于[1,2],也不适用于[1,2,3]

另一个基本问题是,你所谓的“第二组”可能没有意义。 Set 类似 HashSet 的实现以任意顺序维护值。

所以,考虑到这些,你可以做的是:

  1. 先找到第n个值,去掉
  2. 将值添加到已移除的值集中
  3. 重新添加值集。

类似这样的东西(又是伪代码):

int i = 0;
Set<Integer> setToAdd = null;
for (Iterator itr = bigSet.iterator; itr.hasNext(); ++i) {
    Set<Integer> s = itr.next();
    if (i == inputIndex) {
        // remove the set first
        itr.remove();
        setToAdd = s;
        break;
    }
}

// update the set and re-add it back
if (setToAdd != null) {
    setToAdd.add(inputNumber);
    bigSet.add(setToAdd);
}

【讨论】:

    【解决方案2】:

    使用可以像这样使用IteratorsGuava库:

    @Override
    public void add(int a, int b) {
        if (!isValidPair(a, b)) {
            throw new IllegalStateException("!isValidPair does not hold for (a,b)");
        }
    
        Iterators.get(relation.iterator(), a).add(b);
    }
    

    编辑:没有番石榴:

    Iterator<Set<Integer>> iterator = relation.iterator();
    
    for(int i = 0; i < a && iterator.hasNext(); ++i) {
        iterator.next();
    }
    if(iterator.hasNext()) {
        iterator.next().add(b);
    }
    

    【讨论】:

    • 诱人。但我不认为我被允许使用下载的库。谢谢你的建议。
    • 如果循环条件iterator.hasNext() 在整数比较之前失败,迭代器解决方案将中断。我意识到我们应该假设黑盒isValidPair 方法可以解决这个问题,但我们在这里看不到这方面的证据。在这种情况下,使用单独的边界检查方法有点过度设计。
    • 改变你放在 Set 中的值会破坏 Set
    • @Adrian 你确定吗?它将如何破坏 Set?
    • @Lew 添加另一个if(iterator.hasNext()) 应该可以解决吗?
    【解决方案3】:

    使用 for-each 循环让您的生活更轻松。

    public boolean add(int index, int value) {
    // because a and b suck as variable names
    
      if (index < 0 || index >= values.size()) {
        return false;
      }
    
      int iter = 0;
      for (Set<Integer> values : relation) {
        if (iter++ == index) {
          return values.add(value):
        }
      }
      return false;
    }
    

    现在你要弄清楚的是,如果relation 是无序的,就像Set 或关系一样,因为在这种情况下,不同的Set&lt;Integer&gt; 可以匹配相同的index,每次循环执行。

    【讨论】:

    • 改变你放在 Set 中的值会破坏 Set。
    猜你喜欢
    • 2011-05-02
    • 2017-05-11
    • 1970-01-01
    • 2020-07-27
    • 1970-01-01
    • 1970-01-01
    • 2012-08-27
    • 2017-08-17
    • 2017-06-10
    相关资源
    最近更新 更多