【问题标题】:Replace HashSet contents without creating new HashSet Object替换 HashSet 内容而不创建新的 HashSet 对象
【发布时间】:2015-12-23 10:11:51
【问题描述】:

我必须操作大 HashSet 对象下的字符串 我想知道是否有可能操纵现有的 HashSet 对象,无需创建新的 HashSet 对象

以下是我目前的逻辑,其中,我想避免创建第二个 HashSet(set2 对象)。

HashSet<String> set1 = new HashSet<String>();
set1.add("AB.12");
set1.add("CD.34");
set1.add("EF.56");
set1.add("GH.78");

HashSet<String> set2 = new HashSet<String>();
for(String data : set1) {
    set2.add(data.substring(0,2));
}

P.S.:选择 Set 的原因是为了避免重复条目(来自不同的来源)。

【问题讨论】:

  • 你打算做什么操作?
  • “AB.12”和“AB”是两个不同的对象,要保留原来的对象吗?
  • 我想将“AB”保留在我的集合中。
  • 一种方法不是在原始HashSet 中存储String,而是像{AB.12, int fromIndex, int toIndex} 这样的数据结构
  • 是否有特定的理由避免创建第二个哈希集?如果这只是一个内存问题,那么@KishoreReddy 的回答将解决这个问题。否则,对于非列表集合,无法在同一进程中同时插入和删除元素。

标签: java collections hashset


【解决方案1】:

不应更改 HashSet 中的元素以保持集合的完整性。您可以将它们视为不可变元素。

而且由于 HashSet 的顺序没有定义或随着时间的推移保持不变,因此不可能同时添加和删除元素而不会与新元素发生冲突。

但是,如果您想节省内存,您可以同时从 set1 中删除并添加到 set2。

Iterator iter = set1.iterator();

while(iter.hasNext()){
    set2.add(iter.next().substring(0, 2));
    iterator.remove();
}

【讨论】:

  • 删除元素后内存会立即被回收吗?还是他必须等待 GC 启动?
  • “HashSet 中的元素是不可变的。” 不,不一定。
  • 您必须等待 GC 将其启动。它会尽快回收,但不会立即回收。
  • HashSet 中的 @Tom 原始类型 是不可变的。我很抱歉。
  • @Tom,你的文字比我好太多了!我将编辑我的答案以说明这一点。
【解决方案2】:

您的问题没有完美的解决方案。问题是 Set 根据定义不允许索引。再加上String是不可变的,修改数据是不可行的。

我认为你应该考虑改变两件事。

  1. 使用允许您替换元素的数据结构(例如List

2.使用可变数据类型,可能创建您自己的类作为数据类型元素(正如 Victor 在 cmets 中建议的那样)。

这会破坏 HashSet 的内部结构,因为索引是通过散列元素创建的,如果元素发生变化,它可能会消失。

【讨论】:

  • 我建议不要使用 #2。可变类的 equalshashCode 实现是什么?
  • 他可以为 String 创建一个包装类并使用 java 实现。修改对象就像重新分配字符串字段一样简单。或者,他可以推出自己的 char[] 字符串类(这更好,因为他似乎担心内存使用)
  • 你是对的。我忘记了基于哈希的索引。
  • “这会破坏 HashSet 的内部结构” 你说得对:stackoverflow.com/questions/4718009/…
【解决方案3】:

Java Set 不提供有序访问,因此您无法逐个进行替换。

使用List,您可以:

for (int i = 0; i < list.count(); i++) {

    list.set(i, list.get(i).substring(0, 2));
}

请注意,除非您拥有大量数据集,否则构建新的 Set 对象不是问题。


另一种选择是使用Stack

final Stack<String> toProcess = new Stack<>();

for (final String i : set1) {

    toProcess.push(i);
}

set1.clear();

while (!toProcess.isEmpty()) {

    set1.add(toProcess.pop().substring(0, 2));
}

【讨论】:

  • 我已经知道这一点,正如我在查询中已经提到的,我有大量数据。
  • 添加了另一个选项;但我仍然认为List 会更容易。有时,出于效率原因,您必须放松设计。
【解决方案4】:

如果您真的在考虑浪费内存,那么您可以这样做:

   HashSet<String> set2 = new HashSet<String>();

   Iterator<String> ite = set1.iterator();
   while(ite.hasNext()){
         String data = ite.next();
         ite.remove(); //look this
        set2.add(data.substring(0,2));
   }

【讨论】:

  • OP 希望完全避免创建另一个集合
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-19
  • 2012-11-07
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多