J'ai une ArrayList
, une classe Collection de Java, comme suit:
ArrayList<String> animals = new ArrayList<String>();
animals.add("bat");
animals.add("owl");
animals.add("bat");
animals.add("bat");
Comme vous pouvez le constater, la variable animals
ArrayList
se compose de 3 éléments bat
et d'un élément owl
. Je me demandais s'il existe une API dans la structure Collection qui renvoie le nombre d'occurrences bat
ou s'il existe un autre moyen de déterminer le nombre d'occurrences.
J'ai découvert que Collection Multiset
de Google dispose d'une API qui renvoie le nombre total d'occurrences d'un élément. Mais cela n’est compatible qu’avec JDK 1.5. Notre produit est actuellement en JDK 1.6, je ne peux donc pas l'utiliser.
Je suis à peu près sûr que la méthode de la fréquence statique dans Collections serait utile ici:
int occurrences = Collections.frequency(animals, "bat");
C'est comme ça que je le ferais quand même. Je suis à peu près sûr que c'est jdk 1.6 directement.
En Java 8:
Map<String, Long> counts =
list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()));
Cela montre pourquoi il est important de " Faire référence aux objets par leurs interfaces " comme décrit dans Effective Java book.
Si vous codez pour l'implémentation et utilisez ArrayList dans, disons, 50 emplacements dans votre code, lorsque vous trouvez une bonne implémentation "Liste" qui compte les éléments, vous devrez modifier ces 50 emplacements, et probablement casser votre code (s'il est seulement utilisé par vous, ce n'est pas grave, mais s'il est utilisé par quelqu'un d'autre, vous casserez aussi son code)
En programmant sur l'interface, vous pouvez laisser ces 50 emplacements inchangés et remplacer l'implémentation d'ArrayList par "CountItemsList" (par exemple) ou par une autre classe.
Vous trouverez ci-dessous un exemple très simple expliquant comment cela pourrait être écrit. Ceci est seulement un exemple, une liste prête pour la production serait beaucoup plus compliquée.
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" ));
}
}
Principes OO appliqués ici: héritage, polymorphisme, abstraction, encapsulation.
En fait, la classe Collections a une méthode statique appelée: frequency (Collection c, Object o) qui renvoie le nombre d’occurrences de l’élément recherché, mais qui fonctionnera parfaitement pour vous:
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"));
Désolé, il n'y a pas d'appel de méthode simple qui puisse le faire. Tout ce que vous avez à faire est de créer une carte et de compter sa fréquence.
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); }
}
Il n'y a pas de méthode native en Java pour le faire pour vous. Cependant, vous pouvez utiliser IterableUtils # countMatches () d'Apache Commons-Collections pour le faire à votre place.
Je me demande pourquoi vous ne pouvez pas utiliser cette API de collection de Google avec JDK 1.6. Cela dit-il? Je pense que vous pouvez, il ne devrait pas y avoir de problèmes de compatibilité, car il est construit pour une version plus basse. Le cas aurait été différent si cela avait été construit pour 1.6 et que vous exécutiez 1.5.
Est-ce que je me trompe quelque part?
Une approche légèrement plus efficace pourrait être
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();
}
Alternative Java 8 solution utilisant Streams :
long count = animals.stream().filter(animal -> "bat".equals(animal)).count();
Ce que vous voulez, c'est un sac - qui ressemble à un ensemble, mais compte également le nombre d'occurrences. Malheureusement, le framework Java Collections est génial, car il n’a pas d’implication Bag. Pour cela, il faut utiliser Apache Common Collection link text
Pour obtenir directement les occurrences de l'objet de la liste:
int noOfOccurs = Collections.frequency(animals, "bat");
Pour obtenir l'occurrence de la collection Object dans la liste, substituez la méthode equals dans la classe Object comme suit:
@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;
}
Appelez Collections.frequency en tant que:
int noOfOccurs = Collections.frequency(animals, new Animals(1));
Simple moyen de rechercher l'occurrence d'une valeur de chaîne dans un tableau à l'aide des fonctionnalités de 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);
}
Sortie: {Cat = 2, Chèvre = 1, Vache = 1, Vache = 1, Chien = 1}
Vous pouvez remarquer que "Vache" et que la vache ne sont pas considérées comme une même chaîne. Si vous en aviez besoin sous le même compte, utilisez .toLowerCase (). Veuillez trouver l'extrait ci-dessous pour la même chose.
Map<String, Long> couterMap = duplicateList.stream().collect(Collectors.groupingBy(e -> e.toString().toLowerCase(),Collectors.counting()));
Sortie: {cat = 2, vache = 2, chèvre = 1, chien = 1}
Java 8 - autre méthode
String searched = "bat";
long n = IntStream.range(0, animals.size())
.filter(i -> searched.equals(animals.get(i)))
.count();
Si vous utilisez Collections Eclipse , vous pouvez utiliser une variable Bag
. Une MutableBag
peut être renvoyée depuis n'importe quelle implémentation de RichIterable
en appelant 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"));
L'implémentation HashBag
dans EC est soutenue par un MutableObjectIntMap
.
Note: Je suis un partisan des collections Eclipse.
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");
Méthode 1:
Set<String> set = new LinkedHashSet<>();
set.addAll(list);
for (String s : set) {
System.out.println(s + " : " + Collections.frequency(list, s));
}
Méthode 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);
Placez les éléments de l'arraylist dans la table de hachage pour compter la fréquence.
Si vous êtes utilisateur de mon ForEach DSL , vous pouvez le faire avec une requête Count
.
Count<String> query = Count.from(list);
for (Count<Foo> each: query) each.yield = "bat".equals(each.element);
int number = query.result();
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);
}
}
Sortie: 4
Alors faites-le à l'ancienne et faites le vôtre:
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++);
}
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);
Sortie:
=mp= {Ram=2, Boss=1, Shiv=1}
Je ne voulais pas rendre cette affaire plus difficile et je l'ai fait avec deux itérateurs J'ai un HashMap avec LastName -> FirstName. Et ma méthode devrait supprimer les éléments avec 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();
}
}
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");
}