2009-02-03 31 views
123

इस प्रकार मैं एक ArrayList, जावा के एक संग्रह वर्ग है:कैसे एक सूची में एक तत्व की घटनाओं की संख्या की गिनती करने के

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

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

मुझे पता चला कि Google का संग्रह Multiset में एक एपीआई है जो किसी तत्व की घटनाओं की कुल संख्या देता है। लेकिन यह केवल जेडीके 1.5 के साथ संगत है। हमारा उत्पाद वर्तमान में जेडीके 1.6 में है, इसलिए मैं इसका उपयोग नहीं कर सकता।

+0

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

उत्तर

7

जावा में ऐसा करने के लिए जावा में कोई मूल विधि नहीं है। हालांकि, आप अपाचे कॉमन्स-कलेक्शन से IterableUtils#countMatches() का उपयोग अपने लिए कर सकते हैं।

+0

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

+0

@ एमपी तो क्या आप बस उन सभी को कम करते हैं जिनके पास आपकी तुलना में अलग राय है? क्या होगा यदि वह किसी कारण से बैग का उपयोग नहीं कर सकता है या मूल संग्रहों में से किसी एक का उपयोग कर अटक गया है? – Kevin

+0

डाउनवोट, आईएमएचओ के लायक नहीं है। –

10

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

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

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

+0

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

+0

वह सिर्फ 'बल्ले' घटनाओं की संख्या चाहता है। मूल ऐरेलिस्ट पर बस एक बार फिर से शुरू करें और जब भी आप 'बल्ले' देखें तो काउंटर बढ़ाएं। – Frank

5

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

+1

सर्वश्रेष्ठ स्केलेबल समाधान हैं और यदि आप तीसरे पक्ष की सामग्री का उपयोग नहीं कर सकते हैं, तो बस अपना खुद का लिखें। बैग बनाने के लिए रॉकेट विज्ञान नहीं हैं। +1। – paxdiablo

+0

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

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

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

+0

आपके पास एक टाइपो है। इसके बजाय हैश मैप की आवश्यकता है, क्योंकि आप इसे मानचित्र में ले जा रहे हैं। लेकिन 1 के बजाय 0 डालने की गलती थोड़ा और गंभीर है। –

8

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

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

+0

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

+1

यह पुराना असंगत नहीं बनाता है। क्या यह? –

+0

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

1

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

+0

यह वही बात है जो एक कोड नमूना के साथ tweakt कहते हैं। –

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

इससे पता चलता है, यह महत्वपूर्ण क्यों है "Refer to objects by their interfaces" करने के लिए Effective Java पुस्तक में वर्णित है।

यदि आप कार्यान्वयन के लिए कोड करते हैं और आपके कोड में 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")); 
    } 
} 

ओओ सिद्धांत यहां लागू: विरासत, बहुरूपता, अमूर्तता, encapsulation।

+11

अच्छी तरह से किसी को हमेशा विरासत की बजाय संरचना का प्रयास करना चाहिए। आपका कार्यान्वयन अब एरेलिस्टिस्ट पर फंस गया है जब कई बार आप लिंक्डलिस्ट या अन्य चाहते हैं। आपका उदाहरण किसी अन्य लिस्ट को अपने कन्स्ट्रक्टर/फैक्ट्री में ले जाना चाहिए था और एक रैपर लौटाया था। –

+0

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

+2

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

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

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

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

कि कैसे मैं इसे वैसे भी करना चाहते हैं है। मुझे यकीन है कि यह सीधे जेडीके 1.6 है।

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} 
47

जावा 8 में:

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

ई -> ई के बजाय Function.identity() (स्थिर आयात के साथ) का उपयोग करके इसे पढ़ने के लिए थोड़ा अच्छा बनाता है। – Kuchi

+7

यह 'Collections.frequency()' से बेहतर क्यों है?यह कम पठनीय लगता है। – rozina

+0

यह वह नहीं है जिसे पूछा गया था। यह आवश्यक से अधिक काम करता है। –

2

आप Eclipse Collections का उपयोग करते हैं, तो आप एक Bag उपयोग कर सकते हैं। MutableBag को के किसी भी कार्यान्वयन से 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 द्वारा समर्थित है।

नोट: मैं ग्रहण संग्रह के लिए एक committer हूँ।

10

वास्तव में, संग्रह वर्ग एक स्थिर विधि कहा जाता है: आवृत्ति (संग्रह ग, वस्तु ओ) जो तत्व आप खोज रहे हैं की पुनरावृत्ति की संख्या देता है, वैसे, यह आपके लिए पूरी तरह से काम करेगा:

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

लार्स एंडरेन ने आपके उत्तर से 5 साल पहले उसी उत्तर को पोस्ट किया था। –

2

जावा 8 - एक और तरीका

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

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

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

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

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

कॉल Collections.frequency

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

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

    } 

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

स्टैक ओवरफ़्लो में आपका स्वागत है! दूसरों को आपके समाधान को समझना आसान बनाने के लिए अपने कोड को समझाने पर विचार करें। – Antimony

0

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

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

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

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

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

संबंधित मुद्दे