我有一个数组列表,一个Java的集合类,如下所示:

ArrayList<String> animals = new ArrayList<String>();
animals.add("bat");
animals.add("owl");
animals.add("bat");
animals.add("bat");

如您所见,animals数组列表由3个bat元素和1个owl元素组成。我想知道在Collection框架中是否有返回蝙蝠出现次数的API,或者是否有另一种方法来确定出现次数。

我发现谷歌的集合Multiset确实有一个API,返回一个元素的总出现次数。但是这只与JDK 1.5兼容。我们的产品目前是JDK 1.6,所以我不能使用它。


当前回答

List<String> lst = new ArrayList<String>();

lst.add("Ram");
lst.add("Ram");
lst.add("Shiv");
lst.add("Boss");

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

for (String string : lst) {

    if(mp.keySet().contains(string))
    {
        mp.put(string, mp.get(string)+1);

    }else
    {
        mp.put(string, 1);
    }
}

System.out.println("=mp="+mp);

输出:

=mp= {Ram=2, Boss=1, Shiv=1}

其他回答

Java中没有本地方法可以帮你做这些。但是,你可以使用Apache Commons-Collections中的IterableUtils#countMatches()来为你做这件事。

实际上,Collections类有一个名为:frequency(Collection c, Object o)的静态方法,它返回你正在搜索的元素的出现次数,顺便说一下,这将为你完美地工作:

ArrayList<String> animals = new ArrayList<String>();
animals.add("bat");
animals.add("owl");
animals.add("bat");
animals.add("bat");
System.out.println("Freq of bat: "+Collections.frequency(animals, "bat"));

要做到这一点,有几种方法,即:

返回单个元素出现次数的方法:

采集频率

Collections.frequency(animals, "bat");

Java流:

过滤器

animals.stream().filter("bat"::equals).count();

只是迭代思考列表

public static long manually(Collection<?> c, Object o){
    int count = 0;
    for(Object e : c)
        if(e.equals(o))
            count++;
    return count;
}

创建频率映射的方法:

Collectors.groupingBy

Map<String, Long> counts = 
       animals.stream()
              .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

Map<String, Long> map = new HashMap<>();
c.forEach(e -> map.merge(e, 1L, Long::sum));

手动

Map<String, Integer> mp = new HashMap<>();
        animals.forEach(animal -> mp.compute(animal, (k, v) -> (v == null) ? 1 : v + 1));

一个包含所有方法的运行示例:

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Frequency {

    public static int frequency(Collection<?> c, Object o){
        return Collections.frequency(c, o);
    }

    public static long filter(Collection<?> c, Object o){
        return c.stream().filter(o::equals).count();
    }

    public static long manually(Collection<?> c, Object o){
        int count = 0;
        for(Object e : c)
            if(e.equals(o))
                count++;
        return count;
    }

    public static Map<?, Long> mapGroupBy(Collection<?> c){
        return c.stream()
                .collect(Collectors.groupingBy(Function.identity() , Collectors.counting()));
    }

    public static Map<Object, Long> mapMerge(Collection<?> c){
        Map<Object, Long> map = new HashMap<>();
        c.forEach(e -> map.merge(e, 1L, Long::sum));
        return map;
    }

    public static Map<Object, Long> manualMap(Collection<?> c){
        Map<Object, Long> map = new HashMap<>();
        c.forEach(e -> map.compute(e, (k, v) -> (v == null) ? 1 : v + 1));
        return map;
    }


    public static void main(String[] args){
        List<String> animals = new ArrayList<>();
        animals.add("bat");
        animals.add("owl");
        animals.add("bat");
        animals.add("bat");

        System.out.println(frequency(animals, "bat"));
        System.out.println(filter(animals,"bat"));
        System.out.println(manually(animals,"bat"));
        mapGroupBy(animals).forEach((k, v) -> System.out.println(k + " -> "+v));
        mapMerge(animals).forEach((k, v) -> System.out.println(k + " -> "+v));
        manualMap(animals).forEach((k, v) -> System.out.println(k + " -> "+v));
    }
}

方法名称应该反映这些方法正在做什么,但是,我使用名称来反映所使用的方法(假设在当前上下文中这是可以的)。

一个稍微有效一点的方法可能是

Map<String, AtomicInteger> instances = new HashMap<String, AtomicInteger>();

void add(String name) {
     AtomicInteger value = instances.get(name);
     if (value == null) 
        instances.put(name, new AtomicInteger(1));
     else
        value.incrementAndGet();
}

如果使用Eclipse Collections,则可以使用Bag。MutableBag可以通过调用toBag()从RichIterable的任何实现中返回。

MutableList<String> animals = Lists.mutable.with("bat", "owl", "bat", "bat");
MutableBag<String> bag = animals.toBag();
Assert.assertEquals(3, bag.occurrencesOf("bat"));
Assert.assertEquals(1, bag.occurrencesOf("owl"));

Eclipse Collections中的HashBag实现由MutableObjectIntMap支持。

注意:我是Eclipse Collections的提交者。