【问题标题】:What is the most efficient alternative to LinkedHashSet to retrieve an element?LinkedHashSet 检索元素的最有效替代方法是什么?
【发布时间】:2013-05-01 11:46:37
【问题描述】:

除了保留插入顺序之外,还有一个使用 LinkedHashSet 存储一组唯一元素的现有功能。

如果特定元素已存在于 LinkedHashSet 中,则需要检索该元素。即当尝试添加元素时,该方法应检查该元素是否已存在并返回现有元素。 LinkedHashSet 中最多可以有 10000 个元素。

目前实现这一点的方法是在 LinkedHashSet 上使用迭代器

Class CustomObject {
    String id;
    String name;

    CustomObject (String id, String name) {
    this.id = id;
    this.name = name;
    }

    LinkedHashMap<String, LinkedHashSet<CustomObject>> parentRecord = new LinkedHashMap<String, LinkedHashSet<CustomObject>>(4);
    .
    .
    .
    public CustomObject addCustomObject (CustomObject customObject) 
    //Assume the following child node not to be null
        Set<CustomObject> child = parentRecord.get("customObjectName");

        if (child.contains(customObject)) {         
            Iterator<CustomObject> it = child.iterator();       
            while (it.hasNext()) {
               CustomObject node = it.next();           
                   if (node.getId().equals(customObject.getId())) {
                       return node;
                   } 
            }   
        }

        child.add(customObject);

        return customObject;
    }

}

是否有一种有效的替代数据结构方式可以

  1. 存储唯一值

  2. 在尝试添加时返回特定元素(如果它已经存在)

  3. 保留插入顺序(如果可能)

由于被添加的customObject已经在集合中,返回 customObject 本身是有道理的。但是,这不知何故不起作用,因此去了 迭代器,因为我在节点内构建节点。返回的 customObject 可能有子对象 节点。

【问题讨论】:

  • 语义上,如果 Set.contains(object) 返回 true,则您已经拥有存储的元素(或等效实例) - 它是 contains() 的参数!因此,get() 集合中的特定元素没有意义。 Map 似乎更适合您想要实现的目标,因为它可以将不可变标识符映射到实体的特定状态或实例。
  • (注意:上面的代码不会编译。return child; 语句返回的值类型错误,应该是return customObject;
  • 很好,现在更正了代码;-)
  • 我认为,根据我在代码中看到的内容,您不想检查Set 中是否已经存在对象,您想要检查Set 中是否存在具有相同Id 的对象。那是对的吗?如果是这样,您目前得到的答案可能无法在所有情况下都正确执行。

标签: java


【解决方案1】:

使用LinkedHashMap&lt;CustomObject, CustomObject&gt; 而不是LinkedHashSet&lt;CustomObject&gt;

(假设CustomObject.equalsCustomObject.hashcode 使用您当前的“匹配”方法。否则使用带有外部“哈希器”的第三方替代方案...)

方法变成:

public CustomObject addCustomObject (CustomObject customObject) {
    Map<CustomObject, Custom> child = parentRecord.get("customObjectName");

    res = child.get(customObject);
    if (res == null) {   
        child.put(customObject, customObject);
        return customObject;
    } else {
        return res;
    }
}

应该都是O(1)

【讨论】:

    【解决方案2】:

    LinkedHashMapMap 等价于 LinkedHashSet。如果会给你插入顺序遍历,保证键的唯一性,还给你在Map中的项目的持续时间查找。这可能是您的替代方案。

    【讨论】:

      【解决方案3】:

      只需致电contains()。它被指定为 O(1)。

      【讨论】:

      • get() 方法在 LinkedHashSet 上不可用!
      • 错误,糟糕,我的意思是contains()
      • 它应该返回我实际的元素,而不仅仅是检查它是否存在;-)
      • 我不明白。如果您已经拥有已经存在的元素(即您刚刚尝试添加它,但它失败了),为什么不直接返回呢?您为什么要(更不用说)费心费力地从系列中获取它?
      • 不知何故没用,因此选择了迭代器。令人惊讶的是,customObject(正在添加的对象)和节点(由迭代器返回)返回的哈希码是相同的,并且仍然返回 customObject 不起作用。正在调查!
      【解决方案4】:

      根据我对问题的理解。 LinkedHashSet 可以满足您的要求。

      但我假设您已经在您的CustomerObject 中正确实现了equals() and hashcode()

      所以:

      存储唯一值

      Set 为您提供了该功能。

      如果尝试添加时已经存在,则返回特定元素

      使用你的 equals 和 hashcode 方法,就可以了

      if (set.contains(obj)) "return" obj;
      

      上面的“return”不是你方法中的return语句,意思是如果包含true,就取你要插入的对象。因为它等于集合中的 obj。 (不必迭代 Set 并获得相等的对象)

      由于哈希表,contains(obj) 采用 O(1)

      保留广告顺序(如果可能)

      linkedhashSet 基于linkedList,因此保留了插入顺序。

      【讨论】:

      • 由于正在添加的 customObject 已经在集合中,因此返回 customObject 本身是有意义的。但是,这在某种程度上不起作用,因为我正在节点内构建节点。返回的 customObject 可能有子节点。有点特殊的要求。但是你的回答很有用!不能投票,我是新手。
      • @Giri,应该在你的 equals 方法中检查孩子。问题是“你如何定义平等”。
      • @Override public boolean equals (Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CustomObject that = (CustomObject) o; return !(id != null ? !id.equals(that.id) : that.id != null); }
      猜你喜欢
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 2014-09-24
      • 2019-06-30
      • 2010-09-24
      • 2011-07-17
      • 1970-01-01
      相关资源
      最近更新 更多