使用Java,如何比较HashMap中每个条目与同一HashMap中的其他条目而不重复比较?

7

我目前正在使用两个for循环来比较所有条目,但是我得到了重复的比较。由于HashMaps没有排序,我无法弄清楚如何消除已经进行过的比较。例如,我有这样的东西:

    for(Entry<String, String> e1: map.entrySet())
    { 
        for(Entry<String, String> e2: map.entrySet())
        {    
          if (e1.getKey() != e2.getKey())
            {
           //compare e1.getValue() to e2.getValue() 
            }
        }
     }

这样做的问题在于,第一个条目将与第二个条目进行比较,然后是第三个条目等等。但是接着第二个条目将再次与第一个条目进行比较等等。然后第三个条目将和第一个、第二个、第四个条目进行比较等等。有没有更好的方法遍历HashMap以避免重复比较?
额外信息:
更具体地说,我使用的HashMap存储文件名(键)和文件内容(值) - 仅为文本文件。 HashMap已经通过遍历包含要比较的文件的目录来填充。 然后我正在对文件对运行一些算法,以确定每对文件之间的相似度。 我不需要将文件1与文件2进行比较,然后再将文件2与文件1进行比较,因为我只需要比较2个文件一次。 但我确实需要每个文件与其他每个文件进行比较一次。 我刚开始使用HashMap。 agim下面的答案可能适用于我的目的。 但我也会尝试理解Evgeniy Dorofeev和Peter Lawrey的解决方案。 希望这有助于更好地解释事情。

你是否正在尝试查找地图中是否重复出现某个值?如果是,您需要知道哪些键映射到重复的值吗? - russoue
非常感谢大家。我已经添加了一些编辑来更好地解释并希望回答你们的问题。 - Lani1234
7个回答

5

如果不小心处理重复数据的成本可能会比比较重复键的冗余成本还要高。

您可以使用System.identityHashCode(x)对键进行排序。

for(Map.Entry<Key, Value> entry1: map.entrySet()) {
   Key key1 = entry1.getKey();
   int hash1 = System.identityHashCode(key1);
   Value value1 = entry1.getValue();
   for(Map.Entry<Key, Value> entry2: map.entrySet()) {
       Key key2 = entry2.getKey();
       if (key1 > System.identityHashCode(key2)) continue;

       Value value2 = entry1.getValue();
       // compare value1 and value2;
   }
}

2
@Peter - 我认为第7行有一个错别字。它不应该是 if (hash1 > System.identityHashcode(key2)) 吗? - user949300
1
@user949300 谢谢。应该是 identityHashCode - Peter Lawrey
1
@Peter - 第6行应该是Key key2 = entry2.getKey();,对吗?我越读这个解决方案,就越喜欢它了。 - Lani1234
@user1665884 谢谢。两个对象具有相同的键的风险非常小,但我认为这并不太重要。 - Peter Lawrey
应该将 value2 = entry1.getValue(); 的值改为 value2 = entry2.getValue(); 吗? - Nikhil PV

4
这个方案怎么样:
String[] values = map.values().toArray(new String[map.size()]);
for (int i = 0; i < values.length; i++) {
  for (int j = i+1; j<values.length; j++) {
    if (values[i].equals(values[j])) {
      // ...
    }
  }
}

这个解决方案对我来说可行。如果我还创建一个数组来保存键,那么键会按照与值相同的顺序存储在其数组中吗? - Lani1234
1
经典而简单。您还可以使用ArrayList(而不是String[])。即 ArrayList values = new ArrayList(map.values); 然后使用size和get而不是length和[]。 - user949300

1

尝试一下

    HashMap<Object, Object> map = new HashMap<>();
    Iterator<Entry<Object, Object>> i = map.entrySet().iterator();
    while (i.hasNext()) {
        Entry next = i.next();
        i.remove();
        for (Entry e : map.entrySet()) {
            e.equals(next);
        }
    }

请注意,在HashMap中比较键是没有意义的,因为它们总是不相等的。也就是说,我们只能迭代/比较值。

0

如果我理解正确,您只是想知道地图的值中是否有任何重复项? 如果是这样:

Set<String> values = new HashSet<String>(map.values());
boolean hasDuplicates = values.size() != map.size();

这样做可以更高效,如果你在找到第一个重复项后立即退出:
Set<String> values = new HashSet<String>();
for (String value : map.values()) {
  if (!values.add(value)) {
    return true;
  }
}
return false;

0

假设HashMap的条目是整数。 这将返回HashMap中的最大条目。

int maxNum = 0;
for (Object a: hashMap.keySet()) {
  if ((int)hashMap.get(a) > maxNum) {
      maxNum = (int)hashMap.get(a);
  }
}



0
public static boolean compareStringHashMaps(Map<String, String> expectedMap, Map<String, String> actualMap) throws Exception
{
    logger.info("## CommonFunctions | compareStringHashMaps() ## ");
        Iterator iteratorExpectedMap = expectedMap.entrySet().iterator();
        Iterator iteratorActualMap = actualMap.entrySet().iterator();
        boolean flag = true;
        while (iteratorExpectedMap.hasNext() && iteratorActualMap.hasNext()){
            Map.Entry expectedMapEntry = (Map.Entry) iteratorExpectedMap.next();
            Map.Entry actualMapEntry = (Map.Entry) iteratorActualMap.next();
            if(!expectedMapEntry.getKey().toString().trim().equals(actualMapEntry.getKey().toString().trim()))
            {   
                flag = false;
                break;
            }
            else if (!expectedMapEntry.getValue().toString().trim().equals(actualMapEntry.getValue().toString().trim()))
            {
                flag = false;
                break;
            }
        }   
        return flag;

}


1
这与其他 5 种四年前的解决方案有何不同? - Stephen Rauch

-1

你可以尝试使用一个结果的二维数组。如果结果已经被填充,那么就不要再次进行比较。这样做的好处是可以将结果存储起来以备后用。

所以对于一个 int 类型的结果,你可以像这样写:Integer[][] results = new Integer[map.entrySet().size()][map.entrySet().size()]; 这将把数组初始化为 null,并允许你在比较之前检查现有的结果。这里需要注意的一件重要的事情是,每个比较结果都应该在数组中存储两次,除了与自身的比较。例如,索引 1 和索引 2 之间的比较应该存储在 results[1][2]result[2][1] 中。

希望这能帮到你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接