216

我有一个ArrayListJava 的 Collection 类,如下所示:

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

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

我发现 Google 的 CollectionMultiset确实有一个 API 可以返回元素出现的总数。但这仅与 JDK 1.5 兼容。我们的产品目前在 JDK 1.6 中,所以我不能使用它。

4

25 回答 25

398

我很确定 Collections 中的静态频率方法在这里会派上用场:

int occurrences = Collections.frequency(animals, "bat");

反正我就是这样做的。我很确定这是jdk 1.6。

于 2010-03-17T03:35:24.680 回答
138

在 Java 8 中:

Map<String, Long> counts =
    list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()));
于 2014-11-29T19:18:39.743 回答
25

使用Streams的替代Java 8解决方案:

long count = animals.stream().filter(animal -> "bat".equals(animal)).count();
于 2016-02-04T18:22:56.073 回答
24

这说明了为什么“通过接口引用对象”很重要,如Effective Java书中所述。

如果您对实现进行编码并在代码中的 50 个位置使用 ArrayList,那么当您找到一个好的“列表”实现来计算项目时,您将不得不更改所有这 50 个位置,并且可能您必须破坏你的代码(如果它只被你使用,没什么大不了的,但如果它被别人使用,你也会破坏他们的代码)

通过对接口进行编程,您可以让这 50 个位置保持不变,并将实现从 ArrayList 替换为“CountItemsList”(例如)或其他一些类。

下面是一个关于如何编写的非常基本的示例。这只是一个示例,生产就绪列表会复杂得多

import java.util.*;

public class CountItemsList<E> extends ArrayList<E> { 

    // This is private. It is not visible from outside.
    private Map<E,Integer> count = new HashMap<E,Integer>();

    // There are several entry points to this class
    // this is just to show one of them.
    public boolean add( E element  ) { 
        if( !count.containsKey( element ) ){
            count.put( element, 1 );
        } else { 
            count.put( element, count.get( element ) + 1 );
        }
        return super.add( element );
    }

    // This method belongs to CountItemList interface ( or class ) 
    // to used you have to cast.
    public int getCount( E element ) { 
        if( ! count.containsKey( element ) ) {
            return 0;
        }
        return count.get( element );
    }

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

        System.out.println( (( CountItemsList<String> )animals).getCount( "bat" ));
    }
}

这里应用的面向对象原则:继承、多态、抽象、封装。

于 2009-02-03T22:50:28.020 回答
14

抱歉,没有简单的方法调用可以做到这一点。不过,您需要做的就是创建一个地图并用它计算频率。

HashMap<String,int> frequencymap = new HashMap<String,int>();
foreach(String a in animals) {
  if(frequencymap.containsKey(a)) {
    frequencymap.put(a, frequencymap.get(a)+1);
  }
  else{ frequencymap.put(a, 1); }
}
于 2009-02-03T03:35:29.363 回答
10

Java 中没有本地方法可以为您做到这一点。但是,您可以使用Apache Commons-Collections 中的IterableUtils#countMatches()为您完成此操作。

于 2009-02-03T03:33:26.140 回答
9

使用 Java 8 功能在数组中查找字符串值出现的简单方法。

public void checkDuplicateOccurance() {
        List<String> duplicateList = new ArrayList<String>();
        duplicateList.add("Cat");
        duplicateList.add("Dog");
        duplicateList.add("Cat");
        duplicateList.add("cow");
        duplicateList.add("Cow");
        duplicateList.add("Goat");          
        Map<String, Long> couterMap = duplicateList.stream().collect(Collectors.groupingBy(e -> e.toString(),Collectors.counting()));
        System.out.println(couterMap);
    }

输出:{Cat=2, Goat=1, Cow=1, cow=1, Dog=1}

您会注意到“Cow”和cow 不被视为相同的字符串,如果您在相同的计数下需要它,请使用.toLowerCase()。请在下面找到相同的代码段。

Map<String, Long> couterMap = duplicateList.stream().collect(Collectors.groupingBy(e -> e.toString().toLowerCase(),Collectors.counting()));

输出:{cat=2,cow=2,goat=1,dog=1}

于 2017-11-14T10:20:32.357 回答
8

我想知道,为什么不能在 JDK 1.6 中使用 Google 的 Collection API。是这样说的吗?我想你可以,不应该有任何兼容性问题,因为它是为较低版本构建的。如果它是为 1.6 构建的并且您正在运行 1.5,则情况会有所不同。

我在某个地方错了吗?

于 2009-02-03T03:42:23.110 回答
8

实际上,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"));
于 2015-02-14T14:41:35.767 回答
6

一种更有效的方法可能是

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();
}
于 2009-02-03T22:07:52.693 回答
6

直接从列表中获取对象的出现:

int noOfOccurs = Collections.frequency(animals, "bat");

要在列表中获取 Object 集合的出现,请将 Object 类中的 equals 方法重写为:

@Override
public boolean equals(Object o){
    Animals e;
    if(!(o instanceof Animals)){
        return false;
    }else{
        e=(Animals)o;
        if(this.type==e.type()){
            return true;
        }
    }
    return false;
}

Animals(int type){
    this.type = type;
}

将 Collections.frequency 称为:

int noOfOccurs = Collections.frequency(animals, new Animals(1));
于 2016-03-17T23:22:24.797 回答
5

你想要的是一个包——它就像一个集合,但也计算出现的次数。不幸的是,java Collections 框架 - 很棒,因为它们没有 Bag impl。为此,必须使用 Apache Common Collection链接文本

于 2009-02-03T03:35:30.893 回答
5

为了实现这一目标,可以通过多种方式做到这一点,即:

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

收集频率

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

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

于 2021-02-22T18:40:45.430 回答
5
List<String> list = Arrays.asList("as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd", "as", "asda",
        "asd", "urff", "dfkjds", "hfad", "asd", "qadasd" + "as", "asda", "asd", "urff", "dfkjds", "hfad", "asd",
        "qadasd", "as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd");

方法一:

Set<String> set = new LinkedHashSet<>();
set.addAll(list);

for (String s : set) {

    System.out.println(s + " : " + Collections.frequency(list, s));
}

方法二:

int count = 1;
Map<String, Integer> map = new HashMap<>();
Set<String> set1 = new LinkedHashSet<>();
for (String s : list) {
    if (!set1.add(s)) {
        count = map.get(s) + 1;
    }
    map.put(s, count);
    count = 1;

}
System.out.println(map);
于 2017-08-23T17:00:58.177 回答
2

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

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

HashBagEclipse Collections 中的实现由MutableObjectIntMap.

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

于 2015-01-28T22:52:44.263 回答
1

所以用老式的方式来做你自己的:

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

void add(String name) {
     Integer value = instances.get(name);
     if (value == null) {
        value = new Integer(0);
        instances.put(name, value);
     }
     instances.put(name, value++);
}
于 2009-02-03T03:36:25.010 回答
1

将arraylist的元素放入hashMap中统计频率。

于 2009-02-03T04:06:23.593 回答
1

Java 8 - 另一种方法

String searched = "bat";
long n = IntStream.range(0, animals.size())
            .filter(i -> searched.equals(animals.get(i)))
            .count();
于 2016-02-04T10:58:17.093 回答
1
package traversal;

import java.util.ArrayList;
import java.util.List;

public class Occurrance {
    static int count;

    public static void main(String[] args) {
        List<String> ls = new ArrayList<String>();
        ls.add("aa");
        ls.add("aa");
        ls.add("bb");
        ls.add("cc");
        ls.add("dd");
        ls.add("ee");
        ls.add("ee");
        ls.add("aa");
        ls.add("aa");

        for (int i = 0; i < ls.size(); i++) {
            if (ls.get(i) == "aa") {
                count = count + 1;
            }
        }
        System.out.println(count);
    }
}

输出:4

于 2019-06-20T03:45:03.487 回答
0

如果您是我的ForEach DSL的用户,可以通过Count查询来完成。

Count<String> query = Count.from(list);
for (Count<Foo> each: query) each.yield = "bat".equals(each.element);
int number = query.result();
于 2009-03-01T19:22:06.287 回答
0
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}
于 2014-10-08T09:49:25.260 回答
0

您可以将 Java 8 的 groupingBy 功能用于您的用例。

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Test {
    public static void main(String[] args) {
        List<String> animals = new ArrayList<>();

        animals.add("bat");
        animals.add("owl");
        animals.add("bat");
        animals.add("bat");

        Map<String,Long> occurrenceMap =
                animals.stream().collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));
        System.out.println("occurrenceMap:: " + occurrenceMap);
    }
}

输出

occurrenceMap:: {bat=3, owl=1}

于 2021-02-28T03:47:06.007 回答
0

我不想让这种情况变得更加困难,并使用两个迭代器来实现我有一个带有 LastName -> FirstName 的 HashMap。我的方法应该删除具有重复名字的项目。

public static void removeTheFirstNameDuplicates(HashMap<String, String> map)
{

    Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
    Iterator<Map.Entry<String, String>> iter2 = map.entrySet().iterator();
    while(iter.hasNext())
    {
        Map.Entry<String, String> pair = iter.next();
        String name = pair.getValue();
        int i = 0;

        while(iter2.hasNext())
        {

            Map.Entry<String, String> nextPair = iter2.next();
            if (nextPair.getValue().equals(name))
                i++;
        }

        if (i > 1)
            iter.remove();

    }

}
于 2016-08-31T16:11:10.257 回答
0
 Integer[] spam = new Integer[]  {1,2,2,3,4};
 List<Integer>   list=Arrays.asList(spam);

System.out.println(list.stream().collect(Collectors.groupingBy(Function.identity(),Collectors.counting())));
System.out.println(list.stream().collect(Collectors.groupingBy(Function.identity(),HashMap::new,Collectors.counting())));
    

输出

{1=1, 2=2, 3=1, 4=1}

于 2021-03-13T04:33:01.120 回答
0
Map<String,Integer> hm = new HashMap<String, Integer>();
for(String i : animals) {
    Integer j = hm.get(i);
    hm.put(i,(j==null ? 1 : j+1));
}
for(Map.Entry<String, Integer> val : hm.entrySet()) {
    System.out.println(val.getKey()+" occurs : "+val.getValue()+" times");
}
于 2019-02-07T14:28:50.813 回答