Java:如何在hashmap中获取具有相同值的键集

时间:2012-10-03 14:20:38

标签: java hashmap

我有一个如下的hashmap:

1→X

2→; Y

3→X

4-&将Z

现在我想知道值为x(ans:[1,3])的所有键。什么是最好的方法?

蛮力方式是迭代地图并将所有键存储在值为x的数组中。

有没有有效的方法。

由于

10 个答案:

答案 0 :(得分:13)

散列映射是一种优化的结构,用于使用键对值进行关联访问,但在执行反向操作时却没有比使用数组更好的结构。我不认为你可以做得更好然后只是迭代。提高效率的唯一方法是,如果你也有一个反向哈希映射(即哈希映射,你可以在其中保存一个指向所有值的给定值的键数组)。

答案 1 :(得分:10)

您可以使用MultiMap轻松获取所有重复值。

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "x");
map.put(2, "y");
map.put(2, "z");
map.put(3, "x");
map.put(4, "y");
map.put(5, "z");
map.put(6, "x");
map.put(7, "y");

System.out.println("Original map: " + map);

Multimap<String, Integer> multiMap = HashMultimap.create();
for (Entry<Integer, String> entry : map.entrySet()) {
  multiMap.put(entry.getValue(), entry.getKey());
}
System.out.println();

for (Entry<String, Collection<Integer>> entry : multiMap.asMap().entrySet()) {
  System.out.println("Original value: " + entry.getKey() + " was mapped to keys: "
      + entry.getValue());
}

打印出来:

Original map: {1=x, 2=z, 3=x, 4=y, 5=z, 6=x, 7=y}

Original value: z was mapped to keys: [2, 5]
Original value: y was mapped to keys: [4, 7]
Original value: x was mapped to keys: [1, 3, 6]

根据@ noahz 的建议,forMapinvertFrom占用的线数较少,但可以说更复杂:

HashMultimap<String, Integer> multiMap =
    Multimaps.invertFrom(Multimaps.forMap(map), 
        HashMultimap.<String, Integer> create());

取代:

Multimap<String, Integer> multiMap = HashMultimap.create();
for (Entry<Integer, String> entry : map.entrySet()) {
  multiMap.put(entry.getValue(), entry.getKey());
}

答案 2 :(得分:7)

如果Java 8是一个选项,你可以尝试一种流媒体方法:

Map<Integer, String> map = new HashMap<>();
map.put(1, "x");
map.put(2, "y");
map.put(3, "x");
map.put(4, "z");

Map<String, ArrayList<Integer>> reverseMap = new HashMap<>(
    map.entrySet().stream()
        .collect(Collectors.groupingBy(Map.Entry::getValue)).values().stream()
        .collect(Collectors.toMap(
                item -> item.get(0).getValue(),
                item -> new ArrayList<>(
                    item.stream()
                        .map(Map.Entry::getKey)
                        .collect(Collectors.toList())
                ))
        ));

System.out.println(reverseMap);

结果是:

{x=[1, 3], y=[2], z=[4]}

如果首选Java 7:

Map<String, ArrayList<Integer>> reverseMap = new HashMap<>();

for (Map.Entry<Integer,String> entry : map.entrySet()) {
    if (!reverseMap.containsKey(entry.getValue())) {
        reverseMap.put(entry.getValue(), new ArrayList<>());
    }
    ArrayList<Integer> keys = reverseMap.get(entry.getValue());
    keys.add(entry.getKey());
    reverseMap.put(entry.getValue(), keys);
}

有趣的是,在执行(索引,随机('a' - 'z')对的大型地图时,我尝试了每种算法所需的时间。

              10,000,000        20,000,000
Java 7:         615 ms            11624 ms         
Java 8:        1579 ms             2176 ms

答案 3 :(得分:6)

如果您愿意使用图书馆,请使用Google Guava's Multimaps utilities,特别是forMap()结合invertFrom()

答案 4 :(得分:4)

是的,只是蛮力。您还可以通过存储Value中的Multimap来快速创建 - &gt;密钥的集合,代价是更新的内存和运行时成本。

答案 5 :(得分:3)

HashMap计算密钥的hashcode(),而不是值。除非您存储某种附加信息,或考虑使用不同的数据结构,否则我认为唯一可以获得此信息的方法就是蛮力。

如果您需要对值执行有效操作,您应该考虑是否使用了适当的数据结构。

答案 6 :(得分:2)

如果您使用的是散列图,则无法有效地执行此操作,但需要迭代值

答案 7 :(得分:2)

如果您已有地图,则应考虑使用Google's Guava库来过滤您感兴趣的条目。您可以采取以下措施:

final Map<Integer, Character> filtered = Maps.filterValues(unfiltered, new Predicate<Character>() {
    @Override
    public boolean apply(Character ch) {
        return ch == 'x';
    }
});

答案 8 :(得分:2)

我同意George Campbell但是对于java 8我会更容易做到:

Map<String, List<Integer>> reverseMap = map.entrySet()
    .stream()
    .collect(Collectors.groupingBy(Map.Entry::getValue,
        Collectors.mapping(
            Map.Entry::getKey,
            Collectors.toList())));

答案 9 :(得分:-1)

试试这个......

public static void main(String[] args) {
        HashMap<String, String> hashMap = new HashMap<String, String>();
        hashMap.put("cust_tenure", "3_sigma");
        hashMap.put("cust_age", "3_sigma");
        hashMap.put("cust_amb_6m_sav", "3_sigma");
        hashMap.put("cust_amb_6m_chq", "3_sigma");
        hashMap.put("cust_total_prod_6m", "3_sigma");

        HashMap<String, ArrayList<String>> result = new LinkedHashMap<String, ArrayList<String>>();

        for (String key : hashMap.keySet()) {
            ArrayList<String> colName = null;
            if (!result.containsKey(hashMap.get(key))) {
                colName = new ArrayList<String>();
                colName.add(key);
                result.put(hashMap.get(key), colName);
            } else {
                colName = result.get(hashMap.get(key));
                colName.add(key);
                result.put(hashMap.get(key), colName);
            }

            System.out.println(key + "\t" + hashMap.get(key));
        }

        for (String key : result.keySet()) {
            System.out.println(key + "\t" + result.get(key));
        }

        System.out.println(hashMap.size());

    }