次のように、JavaのCollectionクラスであるArrayList
があります。
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フレームワークに、bat
の出現回数を返すAPIがあるのか、または出現回数を決定する別の方法があるのか疑問に思っていました。
GoogleのコレクションMultiset
には、要素の合計出現数を返すAPIがあることがわかりました。ただし、これはJDK 1.5とのみ互換性があります。当社の製品は現在JDK 1.6に含まれているため、使用できません。
コレクションの静的周波数メソッドがここで役立つと確信しています。
int occurrences = Collections.frequency(animals, "bat");
とにかくそうするのです。私はこれがjdk 1.6であると確信しています。
Java 8の場合:
Map<String, Long> counts =
list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()));
これは、 Effective Java bookで説明されているように、「 インターフェースでオブジェクトを参照 」が重要である理由を示しています。
実装にコーディングして、たとえばコード内の50箇所でArrayListを使用する場合、項目をカウントする適切な「リスト」実装を見つけたら、それらの50箇所すべてを変更する必要があります。あなたのコードを壊します(あなただけがそれを使用する場合、大したことはありませんが、他の誰かが使用する場合、あなたのコードも壊します)
インターフェイスにプログラミングすることにより、これらの50の場所を変更せずに、ArrayListから "CountItemsList"(たとえば)または他のクラスに実装を置き換えることができます。
以下は、これをどのように書くことができるかについての非常に基本的なサンプルです。これは単なるサンプルであり、プロダクション準備リストはmuchより複雑になります。
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" ));
}
}
ここで適用されるオブジェクト指向の原則:継承、ポリモーフィズム、抽象化、カプセル化。
申し訳ありませんが、それを実行できる簡単なメソッド呼び出しはありません。ただし、マップを作成して頻度をカウントするだけです。
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); }
}
実際、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"));
Javaには、それを行うためのネイティブメソッドはありません。ただし、Apache Commons-Collectionsの IterableUtils#countMatches() を使用して実行できます。
JDK 1.6でそのGoogleのCollection APIを使用できないのはなぜでしょうか。それはそう言いますか?下位バージョン用に構築されているため、互換性の問題はないはずです。 1.6用にビルドされ、1.5を実行している場合、ケースは異なります。
どこか間違ってる?
もう少し効率的なアプローチは
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();
}
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}
代替Java 8Streamsを使用したソリューション:
long count = animals.stream().filter(animal -> "bat".equals(animal)).count();
欲しいのはバッグです-これはセットのようなものですが、発生回数もカウントします。残念ながらJavaコレクションフレームワーク-Bag implがないので素晴らしいです。そのためには、Apache Common Collectionを使用する必要があります link text
リストからオブジェクトのオカレンスを直接取得するには:
int noOfOccurs = Collections.frequency(animals, "bat");
リスト内のオブジェクトコレクションの出現を取得するには、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));
Java 8-別のメソッド
String searched = "bat";
long n = IntStream.range(0, animals.size())
.filter(i -> searched.equals(animals.get(i)))
.count();
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);
Eclipse Collections を使用する場合、Bag
を使用できます。 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"));
ECのHashBag
実装は、MutableObjectIntMap
によってサポートされています。
注:私はEclipse Collectionsのコミッターです。
配列リストの要素をhashMapに入れて、頻度をカウントします。
あなたが私の ForEach DSL のユーザーであれば、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);
}
}
出力:4
それで、昔ながらの方法でそれをして、あなた自身を転がしてください:
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);
出力:
=mp= {Ram=2, Boss=1, Shiv=1}
私はこのケースをより難しくしたくなく、LastName-> FirstNameのHashMapを持つ2つのイテレーターでそれを作りました。そして、私のメソッドは重複した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");
}