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

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

我有 Multimap,其中包含两个字符串。示例:

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

Multimap 定义(我使用的是 Guava 库):

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

这就是我在 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()) {
        }
    }      

我想计算多图中相同值的出现次数。

因此,如果我计算我的多映射中有多少个值 [key,car](根据我上面给出的示例),结果应该是 2:

我也尝试用多值 HashMap 来实现这个,我用这个来计算它,方式(Storage 是 class 我在对象中存储两个字符串值) :

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

但我没有得到正确的结果。

请尝试此代码。 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());
}

输出:

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

所以第一步是从您的 ListMultimap 创建一个 Map<Integer, List<String>>。您可以通过以下方式执行此操作:

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

然后假设您有一个 List<String>,里面有 carkey。 示例:

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

您只需遍历地图的 values() 并检查 myList 是否包含地图列表中的所有元素。

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

我认为您使用错误的集合来存储数据。根据你写的,你想要一个以整数键和二元组作为值的映射,然后使用 Multiset 来计算频率:

Multiset is a collection that supports order-independent equality, like Set, but may have duplicate elements. 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).

下面的代码假定您正确实现了双元素元组(又名对,或您的 Storage class,但具有正确的 equalshashCode 实现), 比如 this one from 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)]

如果您需要在一个键(整数)下映射几个值(元组),那么您应该将第一行更改为 multimap:

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

以便 m.put(1, anotherTuple) 成为可能并且放置不会覆盖第一个值 (carTuple) 而是将其添加到 1 值列表下。

编辑:

如果你没有need/want额外的依赖,你可以自己实现Tuple2,它看起来像这样class:

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 + ")";
  }
}

您可以通过创建一个以您的多图值作为键并以计数作为值的地图来实现您想要的:

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

这里我使用 Guava 的 Multimap.asMap 方法在原始多图上获得 view,然后将值收集到新地图中。

另一种方式,没有流:

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

这使用 Map.merge 方法通过计算其出现次数来累积相等的值。