Как подсчитать количество вхождений элемента в список

У меня есть ArrayList, класс Collection Java, как показано ниже:

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

Как вы можете видеть, animals ArrayList состоит из трех элементов bat и одного элемента owl. Мне было интересно, есть ли какой-либо API в структуре Collection, который возвращает число вхождений bat или если есть другой способ определить количество вхождений.

Я обнаружил, что Google Collection Multiset имеет API, который возвращает общее количество вхождений элемента. Но это совместимо только с JDK 1.5. Наш продукт в настоящее время находится в JDK 1.6, поэтому я не могу его использовать.

Ответ 1

Я уверен, что статический метод частоты в сборниках пригодится здесь:

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

Вот как я это сделаю. Я уверен, что это jdk 1.6 прямо вверх.

Ответ 2

В Java 8:

Map<String, Long> counts =
    list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()));

Ответ 3

Это показывает, почему важно " Обратитесь к объектам по их интерфейсам", как описано в Эффективная Java.

Если вы кодируете реализацию и используете ArrayList, пусть говорят, 50 мест в вашем коде, когда вы найдете хорошую реализацию "Список", которая подсчитывает элементы, вам придется изменить все эти 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" ));
    }
}

Принципы OO, применяемые здесь: наследование, полиморфизм, абстракция, инкапсуляция.

Ответ 4

Извините, нет простого вызова метода, который может это сделать. Все, что вам нужно сделать, это создать карту и подсчитать частоту с ней.

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

Ответ 5

Собственно, класс Collections имеет статический метод: частота (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"));

Ответ 6

В Java нет встроенного метода, чтобы сделать это для вас. Однако вы можете использовать IterableUtils # countMatches() из коллекции Apache Commons-Collections, чтобы сделать это для вас.

Ответ 7

Интересно, почему вы не можете использовать этот API Google Collection API с JDK 1.6. Это так? Я думаю, что вы можете, не должно быть проблем с совместимостью, поскольку оно построено для более низкой версии. Случай был бы другим, если бы это было построено для 1.6, и вы используете 1.5.

Я где-то ошибаюсь?

Ответ 8

Несколько более эффективный подход может быть

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

Ответ 9

Альтернативное решение Java 8, использующее Потоки:

long count = animals.stream().filter(animal -> "bat".equals(animal)).count();

Ответ 10

Простой способ найти появление строкового значения в массиве с использованием возможностей 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}

Вы можете заметить, что "Корова" и корова не считаются одной и той же строкой, если вы требуете ее в одном подсчете, используйте .toLowerCase(). Ниже приведен фрагмент ниже.

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

Результат: {cat = 2, cow = 2, goat = 1, dog = 1}

Ответ 11

То, что вы хотите, это сумка, которая похожа на набор, но также учитывает количество случаев. К сожалению, фреймворк java Collections - великолепен, так как у него нет пакета Bag. Для этого необходимо использовать текст ссылки Apache Common Collection

Ответ 12

Чтобы получить вхождения объекта из списка напрямую:

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

Чтобы получить появление внутреннего списка объектов, переопределите метод equals в классе Object как:

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

Ответ 13

Если вы используете Eclipse Collections, вы можете использовать Bag. A MutableBag может быть возвращен из любой реализации 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"));

Реализация HashBag в EC поддерживается MutableObjectIntMap.

Примечание: Я являюсь коммиттером для коллекций Eclipse.

Ответ 14

Java 8 - другой метод

String searched = "bat";
long n = IntStream.range(0, animals.size())
            .filter(i -> searched.equals(animals.get(i)))
            .count();

Ответ 15

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

Способ 1:

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

for (String s : set) {

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

Способ 2:

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

Ответ 16

Поместите элементы arraylist в hashMap, чтобы подсчитать частоту.

Ответ 17

Итак, сделайте это старомодным способом и бросьте свой собственный:

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

Ответ 18

Если вы являетесь пользователем моего ForEach DSL, это можно сделать с помощью запроса Count.

Count<String> query = Count.from(list);
for (Count<Foo> each: query) each.yield = "bat".equals(each.element);
int number = query.result();

Ответ 19

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}

Ответ 20

Я не хотел затруднять этот случай и сделал это с двумя итераторами У меня есть HashMap с LastName → FirstName. И мой метод должен удалять элементы с dulicate FirstName.

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

    }

}

Ответ 21

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

Ответ 22

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