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

时间:2018-01-16 11:36:51

标签: java hashmap guava multimap

我有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()) {
        }
    }      

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

因此,如果我在多图中计算[key,car]的值(我上面给出的每个例子),结果应为2:

  • [key,car] = 2
  • 的出现次数
  • [key,blue] = 1
  • 的出现次数

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

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

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

4 个答案:

答案 0 :(得分:2)

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

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

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

另一种方式,没有流:

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

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

答案 1 :(得分:1)

请尝试此代码。 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

答案 2 :(得分:1)

因此,第一步是从ListMultimap创建Map<Integer, List<String>> collect = map_multi.entries() .stream() .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); 。您可以通过以下方式执行此操作:

List<String>

然后我们假设您有一个car,其中包含key List<String> myList = List.of("key", "car"); // java 9 。  例如:

values()

您只需遍历地图的myList,然后检查long count = collect.values() .stream() .filter(list -> list.containsAll(myList)) .count(); 是否包含地图列表中的所有元素。

{{1}}

答案 3 :(得分:1)

我认为您使用错误的收藏来存储您的数据。根据您所写的内容,您需要一个带整数键和两元素元组的映射作为值,然后使用Multiset计算频率:

  

Multiset一个支持与顺序无关的相等的集合,如Set,但可能包含重复的元素。 multiset有时也称为 bag

     

多个集合中彼此相等的元素称为相同单个元素的出现。 多重集中元素的出现次数称为该元素的计数(术语&#34;频率&#34;和&#34;多重性&#34;等效,但不是在此API中使用。)

下面的代码假设您正确实现了双元素元组(也就是对,或Storage类,但具有正确的equalshashCode实现),如{{3 }}:

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)]

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

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

这样m.put(1, anotherTuple)是可能的,并且不会覆盖第一个值(carTuple),而是将其添加到1值列表下。

<强> 编辑:

如果您不需要/想要其他依赖项,您可以自己实施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 + ")";
  }
}