简体   繁体   English

如何计算MultiMap中每个值的出现次数? (Java)的

[英]How to count occurrences for each value in MultiMap ? (java)

I have Multimap , which contains two strings. 我有Multimap ,其中包含两个字符串。 Example: 例:

1 = [key,car],  
2 = [key,blue],
3 = [key,car]

Multimap definition (I am using Guava library): 多图定义(我正在使用Guava库):

ListMultimap<Integer, String> map_multi = ArrayListMultimap.create(); 

And this is how I put values in MultiMap: 这就是我将值放在MultiMap中的方式:

for (int i = 0; i < list.size(); i++) {
        if (i + 1 < list.size()) {

            multimap.put(i,(String) list.get(i));
            multimap.put(i,(String) list.get(i+1));

        } else if (i + 1 == list.size()) {
        }
    }      

I want to count the occurrences of the same value inside the multimap. 我想计算多图内相同值的出现。

So the result should be 2 if i count how many values [key,car] are (per example I have given above) in my multimap: 因此,如果我在多张地图中算出[key,car]值是多少(按照上面的示例,我应该给出2):

  • occurrences of [key,car] = 2 [key,car] = 2
  • occurrences of [key,blue] = 1 [key,blue] = 1的出现

I have also tried to implement this with multi value HashMap and I was counting it with this, way ( Storage is class where I store two string values inside object): 我也尝试过使用多值HashMap来实现这一点,并以此方式进行计数( Storage是类,我在对象内部存储了两个字符串值):

B = Collections.frequency(new ArrayList<Storage>(map.values()), map.get(number));

But I don't get the right results. 但是我没有得到正确的结果。

You can achieve what you want by creating a map that has your multimap values as the keys and the count as the value: 您可以通过创建一个以多图值作为键并将计数作为值的图来实现所需的目标:

Map<Collection<String>, Long> result = map_multi.asMap().values().stream()
    .collect(Collectors.groupingBy(v -> v, Collectors.counting()));

Here I've used Guava's Multimap.asMap method to get a view over the original multimap, then collected the values into a new map. 在这里,我使用了Guava的Multimap.asMap方法来获取原始多图的视图 ,然后将值收集到新图中。

Another way, without streams: 没有流的另一种方式:

Map<Collection<String>, Integer> result = new HashMap<>();
map_multi.asMap().values().forEach(v -> result.merge(v, 1, Integer::sum));

This uses the Map.merge method to accumulate equal values by counting its occurrences. 这使用Map.merge方法通过计算其出现次数来累积相等的值。

Please try this code. 请尝试此代码。 map_multi.get(key).size() is your answer. map_multi.get(key).size()是您的答案。

ListMultimap<Integer, String> map_multi = ArrayListMultimap.create();
map_multi.put(1, "car");
map_multi.put(2, "blue");
map_multi.put(3, "apple");
map_multi.put(1, "car");

for (Integer key : map_multi.keySet()) {
    System.out.println(map_multi.get(key).get(0) + " occurances: " + map_multi.get(key).size());
}

Output: 输出:

car occurances: 2
blue occurances: 1
apple occurances: 1

So the first step is to create a Map<Integer, List<String>> from your ListMultimap . 因此,第一步是从ListMultimap创建Map<Integer, List<String>> You can do this in the following way: 您可以通过以下方式执行此操作:

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

Then let's say you have a List<String> with car and key in it. 然后,假设您有一个带有carkeyList<String> Example: 例:

 List<String> myList = List.of("key", "car"); // java 9

You just iterate through the values() of the map and check if myList contains all elements from map's lists. 您只需遍历地图的values()并检查myList包含地图列表中的所有元素。

long count = collect.values()
            .stream()
            .filter(list -> list.containsAll(myList))
            .count();

I think you're using wrong collection to store your data. 我认为您使用了错误的集合来存储数据。 Based on what you wrote, you want a map with integer keys and two-element tuples as values and then use Multiset to count frequencies: 根据您所写的内容,您需要一个以整数键和两个元素的元组为值的映射,然后使用Multiset来计数频率:

Multiset is a collection that supports order-independent equality, like Set , but may have duplicate elements. Multiset一个集合,它支持与顺序无关的相等性,例如Set ,但是可能具有重复的元素。 A multiset is also sometimes called a bag . 多件有时也称为书包

Elements of a multiset that are equal to one another are referred to as occurrences of the same single element. 多个元素彼此相等的元素称为同一元素的出现。 The total number of occurrences of an element in a multiset is called the count of that element (the terms "frequency" and "multiplicity" are equivalent , but not used in this API). 元素在多集中出现的总数称为该元素的计数(术语“频率”和“多重性”是等效的 ,但在此API中未使用)。

The code below assumes you have proper implementation of two-element tuple (aka pair, or your Storage class, but with proper equals and hashCode implementations), like this one from jOOL : 下面的代码假定您已经正确地实现了两个元素的元组(aka对,或您的Storage类,但是具有适当的equalshashCode实现),例如jOOL的一个

HashMap<Integer, Tuple2<String, String>> m = new HashMap<>();
Tuple2<String, String> carTuple = new Tuple2<>("key", "car");
Tuple2<String, String> blueTuple = new Tuple2<>("key", "blue");

m.put(1, carTuple);
m.put(2, blueTuple);
m.put(3, carTuple);

ImmutableMultiset<Tuple2<String, String>> occurrences = 
    ImmutableMultiset.copyOf(m.values());
System.out.println(occurrences); // [(key, car) x 2, (key, blue)]

If you need to have few values (tuples) mapped under one key (integer), then you should change the first line to multimap: 如果需要在一个键(整数)下映射的值(元组)很少,则应将第一行更改为多图:

ListMultimap<Integer, Tuple2<String, String>> m = ArrayListMultimap.create();

so that m.put(1, anotherTuple) is possible and putting doesn't override first value ( carTuple ) but rather adds it under 1 values list. 因此m.put(1, anotherTuple)是可能的,并且put不会覆盖第一个值( carTuple ),而是将其添加到1值列表下。

EDIT: 编辑:

You can implement Tuple2 yourself if you don't need/want additional dependency, it could look like this class: 如果不需要/想要其他依赖项,则可以自己实现Tuple2 ,它看起来像此类:

public class Tuple2<T1, T2> {

  public final T1 v1;
  public final T2 v2;

  public Tuple2(T1 v1, T2 v2) {
    this.v1 = v1;
    this.v2 = v2;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof Tuple2)) {
      return false;
    }
    @SuppressWarnings({"unchecked", "rawtypes"}) final Tuple2<T1, T2> that = (Tuple2) o;
    return Objects.equals(v1, that.v1) && Objects.equals(v2, that.v2);
  }

  @Override
  public int hashCode() {
    return Objects.hash(v1, v2);
  }

  @Override
  public String toString() {
    return "(" + v1 + ", " + v2 + ")";
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM