可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have an ArrayList
, a Collection class of Java, as follows:
ArrayList<String> animals = new ArrayList<String>();
animals.add(\"bat\");
animals.add(\"owl\");
animals.add(\"bat\");
animals.add(\"bat\");
As you can see, the animals
ArrayList
consists of 3 bat
elements and one owl
element. I was wondering if there is any API in the Collection framework that returns the number of bat
occurrences or if there is another way to determine the number of occurrences.
I found that Google\'s Collection Multiset
does have an API that returns the total number of occurrences of an element. But that is compatible only with JDK 1.5. Our product is currently in JDK 1.6, so I cannot use it.
回答1:
I\'m pretty sure the static frequency-method in Collections would come in handy here:
int occurrences = Collections.frequency(animals, \"bat\");
That\'s how I\'d do it anyway. I\'m pretty sure this is jdk 1.6 straight up.
回答2:
In Java 8:
Map<String, Long> counts =
list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()));
回答3:
This shows, why it is important to \"Refer to objects by their interfaces\" as described in Effective Java book.
If you code to the implementation and use ArrayList in let\'s say, 50 places in your code, when you find a good \"List\" implementation that count the items, you will have to change all those 50 places, and probably you\'ll have to break your code ( if it is only used by you there is not a big deal, but if it is used by someone else uses, you\'ll break their code too)
By programming to the interface you can let those 50 places unchanged and replace the implementation from ArrayList to \"CountItemsList\" (for instance ) or some other class.
Below is a very basic sample on how this could be written. This is only a sample, a production ready List would be much more complicated.
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 principles applied here: inheritance, polymorphism, abstraction, encapsulation.
回答4:
Actually, Collections class has a static method called : frequency(Collection c, Object o) which returns the number of occurrences of the element you are searching for, by the way, this will work perfectly for you:
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\"));
回答5:
Sorry there\'s no simple method call that can do it. All you\'d need to do though is create a map and count frequency with it.
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); }
}
回答6:
There is no native method in Java to do that for you. However, you can use IterableUtils#countMatches() from Apache Commons-Collections to do it for you.
回答7:
I wonder, why you can\'t use that Google\'s Collection API with JDK 1.6. Does it say so? I think you can, there should not be any compatibility issues, as it is built for a lower version. The case would have been different if that were built for 1.6 and you are running 1.5.
Am I wrong somewhere?
回答8:
A slightly more efficient approach might be
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:
Alternative Java 8 solution using Streams:
long count = animals.stream().filter(animal -> \"bat\".equals(animal)).count();
回答10:
What you want is a Bag - which is like a set but also counts the number of occurances. Unfortunately the java Collections framework - great as they are dont have a Bag impl. For that one must use the Apache Common Collection link text
回答11:
To get the occurrences of the object from the list directly:
int noOfOccurs = Collections.frequency(animals, \"bat\");
To get the occurrence of the Object collection inside list, override the equals method in the Object class as:
@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;
}
Call the Collections.frequency as:
int noOfOccurs = Collections.frequency(animals, new Animals(1));
回答12:
Simple Way to find the occurrence of string value in an array using Java 8 features.
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);
}
Output : {Cat=2, Goat=1, Cow=1, cow=1, Dog=1}
You can notice \"Cow\" and cow are not considered as same string, in case you required it under same count, use .toLowerCase(). Please find the snippet below for the same.
Map<String, Long> couterMap = duplicateList.stream().collect(Collectors.groupingBy(e -> e.toString().toLowerCase(),Collectors.counting()));
Output : {cat=2, cow=2, goat=1, dog=1}
回答13:
Java 8 - another method
String searched = \"bat\";
long n = IntStream.range(0, animals.size())
.filter(i -> searched.equals(animals.get(i)))
.count();
回答14:
If you use Eclipse Collections, you can use a Bag
. A MutableBag
can be returned from any implementation of RichIterable
by calling 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\"));
The HashBag
implementation in EC is backed by a MutableObjectIntMap
.
Note: I am a committer for Eclipse Collections.
回答15:
Put the elements of the arraylist in the hashMap to count the frequency.
回答16:
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\");
Method 1:
Set<String> set = new LinkedHashSet<>();
set.addAll(list);
for (String s : set) {
System.out.println(s + \" : \" + Collections.frequency(list, s));
}
Method 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);
回答17:
So do it the old fashioned way and roll your own:
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:
If you are a user of my ForEach DSL, it can be done with a Count
query.
Count<String> query = Count.from(list);
for (Count<Foo> each: query) each.yield = \"bat\".equals(each.element);
int number = query.result();
回答19:
I didn\'t want to make this case more difficult and made it with two iterators
I have a HashMap with LastName -> FirstName. And my method should delete items with 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();
}
}
回答20:
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);
Output:
=mp= {Ram=2, Boss=1, Shiv=1}