किसी सूची में किसी तत्व के होने की संख्या की गणना कैसे करें


173

मेरे पास एक ArrayList, जावा का एक संग्रह वर्ग है, निम्नानुसार है:

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

जैसा कि आप देख सकते हैं, animals ArrayList3 batतत्वों और एक owlतत्व शामिल हैं। मैं सोच रहा था कि क्या संग्रह ढांचे में कोई एपीआई है जो batघटनाओं की संख्या लौटाता है या यदि घटनाओं की संख्या निर्धारित करने का कोई अन्य तरीका है।

मैंने पाया कि Google के संग्रह Multisetमें एक API है जो किसी तत्व की कुल संख्या को लौटाता है। लेकिन यह केवल JDK 1.5 के साथ संगत है। हमारा उत्पाद वर्तमान में JDK 1.6 में है, इसलिए मैं इसका उपयोग नहीं कर सकता।


यही कारण है कि आपको कार्यान्वयन के बजाय इंटरफ़ेस पर कार्यक्रम करना चाहिए। यदि आप सही संग्रह खोजने के लिए होते हैं, तो आपको उस संग्रह का उपयोग करने के लिए प्रकार बदलने की आवश्यकता होगी। मैं इस पर जवाब पोस्ट करूंगा।
OscarRyz

जवाबों:


333

मुझे पूरा यकीन है कि संग्रह में स्थिर आवृत्ति-विधि यहाँ काम आएगी:

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

मैं इसे वैसे भी कैसे करूँगा। मुझे पूरा यकीन है कि यह jdk 1.6 सीधा है।


हमेशा जेआरई से एपी को प्राथमिकता दें, जो परियोजना में एक और निर्भरता जोड़ते हैं। और पहिया को फिर से संगठित नहीं करना है !!
फर्नांडो।

इसे JDK 5 में पेश किया गया था (हालाँकि इससे पहले कोई भी एक संस्करण का उपयोग नहीं करता है, इसलिए इससे कोई फर्क नहीं पड़ता) docs.oracle.com/javase/8/docs/technotes/guides/collections/…
मिनियन जिम

105

जावा 8 में:

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

6
ई -> ई के बजाय फंक्शन.सिटी () (स्थिर आयात के साथ) का उपयोग करना इसे पढ़ने के लिए थोड़ा अच्छा बनाता है।
कुची

8
इससे बेहतर क्यों है Collections.frequency()? यह कम पठनीय लगता है।
रोजिना

यह वह नहीं है जो मांगा गया था। यह आवश्यकता से अधिक कार्य करता है।
एलेक्स वर्डेन

8
यह उस चीज़ से अधिक हो सकता है जो माँगी गई थी, लेकिन यह ठीक वही है जो मैं चाहता था (उनकी सूची में अलग-अलग तत्वों का एक नक्शा प्राप्त करें)। इसके अलावा, जब मैंने खोजा तो यह प्रश्न Google में शीर्ष परिणाम था।
KJP

@rozina आपको सभी पास एक ही पास में मिलते हैं।
atoMerz

22

यह दिखाता है, क्यों प्रभावी जावा पुस्तक में वर्णित के रूप में " उनके इंटरफेस द्वारा वस्तुओं को देखें " महत्वपूर्ण है ।

यदि आप कार्यान्वयन के लिए कोड देते हैं और आइए 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 सिद्धांत यहां लागू होते हैं: वंशानुक्रम, बहुरूपता, अमूर्तता, इनकैप्सुलेशन।


12
खैर किसी को हमेशा विरासत के बजाय रचना की कोशिश करनी चाहिए। आपका कार्यान्वयन अब ArrayList से चिपक गया है जब कोई लिंकडलिस्ट या अन्य चाहने वाला समय हो सकता है। आपके उदाहरण को अपने निर्माता / कारखाने में एक और LIst लेना चाहिए और एक रैपर वापस करना चाहिए।
एम.पी.

मैं पूर्णतः सन्तुष्ट हुँ। मैंने नमूने में इनहेरिटेंस का उपयोग किया है इसका कारण यह है कि रचना की तुलना में वंशानुक्रम का उपयोग करके चल रहे उदाहरण को प्रदर्शित करना अधिक आसान है (सूची इंटरफ़ेस को लागू करने के लिए)। वंशानुक्रम उच्चतम युग्मन बनाता है।
OscarRyz

2
लेकिन इसका नामकरण करके यह CountItemsList का अर्थ है कि यह दो चीजें करता है, यह वस्तुओं को गिनता है और यह एक सूची है। मुझे लगता है कि उस वर्ग के लिए सिर्फ एक ही ज़िम्मेदारी है, घटनाओं को गिनना, उतना ही सरल होगा और आपको सूची इंटरफ़ेस को लागू करने की आवश्यकता नहीं होगी।
फ़्लोब

11

क्षमा करें कोई सरल विधि कॉल नहीं है जो इसे कर सके। हालांकि आपको एक मानचित्र बनाने और उसके साथ आवृत्ति की गणना करने की आवश्यकता होगी।

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

यह वास्तव में एक मापनीय समाधान नहीं है - कल्पना करें कि एमएम के डेटा सेट में सैकड़ों और हजारों प्रविष्टियां थीं और एमएम प्रत्येक प्रविष्टि के लिए आवृत्तियों को जानना चाहते थे। यह संभावित रूप से एक बहुत महंगा काम हो सकता है - खासकर जब इसे करने के लिए बहुत बेहतर तरीके हैं।
एम.पी.

हां, यह एक अच्छा समाधान नहीं हो सकता है, इसका मतलब गलत नहीं है।
आदिल अंसारी

1
@ अहमदाबाद, मुझे नहीं लगता कि वह सचमुच 4-तत्व संग्रह में बल्लेबाजी की संख्या चाहता है, मुझे लगता है कि यह सिर्फ नमूना डेटा था इसलिए हम बेहतर समझेंगे :-)।
paxdiablo

2
@ वाइन 2/2। प्रोग्रामिंग अब चीजों को ठीक से करने के बारे में है, इसलिए हम सिरदर्द का कारण नहीं बनते हैं या किसी और के लिए एक बुरा अनुभव यह भविष्य में एक उपयोगकर्ता या किसी अन्य कोडर का होना चाहिए। पुनश्च: अधिक कोड आपके लिखने का मौका अधिक कुछ गलत हो सकता है।
एम.पी.

2
@ एमपी: कृपया समझाएं कि यह एक मापनीय समाधान क्यों नहीं है। रे हिदायत प्रत्येक टोकन के लिए एक आवृत्ति गणना का निर्माण कर रहा है ताकि प्रत्येक टोकन को फिर से देखा जा सके। एक बेहतर उपाय क्या है?
stackoverflowuser2010

10

आपके लिए ऐसा करने के लिए जावा में कोई मूल विधि नहीं है। हालाँकि, आप इसे करने के लिए Apache Commons-Collection से IterableUtils # countMatches () का उपयोग कर सकते हैं ।


नीचे मेरे उत्तर का संदर्भ लें - सही उत्तर एक ऐसी संरचना का उपयोग करना है, जो किसी क्वेरी के किए जाने के बाद शुरू से अंत तक प्रविष्टियों को गिनने के बजाय भीख से गिनती के विचार का समर्थन करता है।
एम.पी.

@ एमपी तो आप केवल उन सभी को नीचा दिखाते हैं जो आपसे अलग राय रखते हैं? क्या होगा यदि वह किसी कारण से एक थैले का उपयोग नहीं कर सकता है या मूल संग्रह में से एक का उपयोग करने के साथ फंस गया है?
केविन

-1 एक खराब हारे होने के लिए :-) मुझे लगता है कि mP ने आपको नीचे उतारा क्योंकि आपका समाधान हर बार जब आप परिणाम चाहते हैं। एक थैला केवल प्रविष्टि पर थोड़ा समय खर्च करता है। डेटाबेस की तरह, इन प्रकार की संरचनाएं "लिखने की तुलना में अधिक पढ़ी जाती हैं" इसलिए यह कम लागत के विकल्प का उपयोग करने के लिए समझ में आता है।
paxdiablo

और ऐसा लगता है कि आपके उत्तर के लिए भी गैर-देशी सामान की आवश्यकता है, इसलिए आपकी टिप्पणी थोड़ी अजीब लगती है।
paxdiablo

आप दोनों लोगों को धन्यवाद। मेरा मानना ​​है कि दो दृष्टिकोणों में से एक या दोनों काम कर सकते हैं। मैं इसे कल एक कोशिश दूंगा।
एम.एम.

9

दरअसल, कलेक्शन क्लास में एक स्टैटिक विधि होती है, जिसे कहा जाता है: फ़्रीक्वेंसी (कलेक्शन c, ऑब्जेक्ट ओ) जो आपके द्वारा खोजे जा रहे तत्व की घटनाओं की संख्या लौटाता है, वैसे यह आपके लिए पूरी तरह से काम करेगा:

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

27
लार्स एंड्रेन ने आपका 5 साल पहले भी यही जवाब पोस्ट किया था।
फेबियन बार्नी

9

वैकल्पिक जावा 8 धाराओं का उपयोग कर समाधान :

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

8

मुझे आश्चर्य है, कि आप JDK 1.6 के साथ Google के संग्रह API का उपयोग क्यों नहीं कर सकते हैं। क्या यह ऐसा कहता है? मुझे लगता है कि आप कर सकते हैं, इसमें कोई संगतता मुद्दे नहीं होने चाहिए, क्योंकि यह एक कम संस्करण के लिए बनाया गया है। अगर मामला 1.6 के लिए बनाया गया होता और आप 1.5 चला रहे होते तो मामला अलग होता।

क्या मैं कहीं गलत हूं?


उन्होंने स्पष्ट रूप से उल्लेख किया है कि वे अपने api को jdk 1.6 में अपग्रेड करने की प्रक्रिया में हैं।
एम.एम.

1
यह पुराना असंगत नहीं बनाता है। क्या यह?
आदिल अंसारी

यह नहीं होना चाहिए। लेकिन जिस तरह से वे अस्वीकरण फेंक रहे थे, मुझे उनके 0.9 संस्करण
एमएम

हम इसे 1.6 के साथ उपयोग करते हैं। यह कहां कहता है कि यह केवल 1.5 के साथ संगत है?
पैट्रिक

2
1.6 में "अपग्रेड करने" से उनका मतलब है "1.6 में नए सामान का लाभ उठाने के लिए अपग्रेड करना", "1.6 के साथ संगतता को ठीक नहीं करना"।
एडम जस्किविक्ज़

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

6

सीधे सूची से ऑब्जेक्ट की घटनाओं को प्राप्त करने के लिए:

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

सूची के अंदर ऑब्जेक्ट संग्रह की घटना प्राप्त करने के लिए, ऑब्जेक्ट क्लास में समान विधि को ओवरराइड करें:

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

इस रूप में संग्रह कॉल करें:

int noOfOccurs = Collections.frequency(animals, new Animals(1));

6

जावा 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);
    }

आउटपुट: {कैट = २, बकरी = १, गाय = १, गाय = १, कुत्ता = १}

आप "गाय" को नोटिस कर सकते हैं और गाय को एक ही स्ट्रिंग के रूप में नहीं माना जाता है, यदि आपको एक ही गणना के तहत इसकी आवश्यकता है, तो .toLowerCase () का उपयोग करें। कृपया उसी के लिए नीचे स्निपेट ढूंढें।

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

आउटपुट: {बिल्ली = २, गाय = २, बकरी = १, कुत्ता = १}


नाइट: क्योंकि सूची स्ट्रिंग्स की एक सूची है, toString()अनावश्यक है। आप बस कर सकते हैं:duplicateList.stream().collect(Collectors.groupingBy(e -> e,Collectors.counting()));
तद

5

आप जो चाहते हैं वह एक थैला है - जो एक सेट की तरह है, लेकिन घटनाओं की संख्या भी गिना जाता है। दुर्भाग्य से जावा संग्रह रूपरेखा - महान के रूप में वे एक बैग निहित नहीं है। उसके लिए अपाचे कॉमन कलेक्शन लिंक टेक्स्ट का उपयोग करना चाहिए


1
सबसे अच्छा स्केलेबल समाधान और, यदि आप तीसरे पक्ष के सामान का उपयोग नहीं कर सकते हैं, तो बस अपना लिखो। बैग बनाने के लिए रॉकेट साइंस नहीं हैं। +1।
paxdiablo

कुछ अस्पष्ट उत्तर देने के लिए नीचा दिखाया गया है जबकि अन्य ने आवृत्ति-गणना डेटा संरचनाओं के लिए कार्यान्वयन प्रदान किया है। जिस The बैग ’डेटा संरचना से आप जुड़े हैं, वह ओपी के प्रश्न का एक उपयुक्त समाधान नहीं है; उस 'बैग' संरचना का उद्देश्य टोकन की प्रतियों की एक विशिष्ट संख्या को पकड़ना है, न कि टोकन की घटनाओं की संख्या को गिनना।
stackoverflowuser2010

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

ढेर अतिप्रवाह में आपका स्वागत है! अपने समाधान को समझने के लिए दूसरों के लिए इसे आसान बनाने के लिए अपने कोड को समझाने पर विचार करें।
एंटीमनी

2

यदि आप ग्रहण संग्रह का उपयोग करते हैं , तो आप एक का उपयोग कर सकते हैं 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ग्रहण संग्रह में कार्यान्वयन एक के द्वारा समर्थित हैMutableObjectIntMap

नोट: मैं एक्लिप्स कलेक्शंस के लिए कमिट हूं।


1

आवृत्ति को गिनने के लिए हैश मैप में सरणी सूची के तत्वों को रखें।


यह बिल्कुल वैसी ही बात है जैसे कि चिकोटी एक कोड नमूने के साथ कहता है।
एम.पी.

1

जावा 8 - एक अन्य विधि

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

0

तो इसे पुराने तरीके से करें और अपना रोल करें:

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

उचित "सिंक्रनाइज़" के साथ, यदि आवश्यक हो, तो दौड़ की स्थिति से बचने के लिए। लेकिन मैं अभी भी इसे अपनी कक्षा में देखना पसंद करूंगा।
paxdiablo

आपके पास एक टाइपो है। इसके बजाय आपको HashMap चाहिए, जैसा कि आप इसे Map में ले रहे हैं। लेकिन 1 के बजाय 0 डालने की गलती थोड़ी अधिक गंभीर है।
आदिल अंसारी

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

0

मैं इस मामले को और अधिक कठिन नहीं बनाना चाहता था और मैंने इसे दो पुनरावृत्तियों के साथ बनाया है मेरे पास लास्टनाम है - लास्टनाम के साथ। और मेरी विधि 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();

    }

}

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}

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

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

आउटपुट: ४


यह स्टैक ओवरफ्लो पर एक अच्छा अभ्यास है ताकि यह समझा जाए कि आपके समाधान को काम करना चाहिए या मौजूदा समाधानों से बेहतर है। अधिक जानकारी के लिए उत्तर कैसे पढ़ें ।
शमूएल एलवाई
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.