इट्रेटर की गिनती / लंबाई / आकार प्राप्त करने का सबसे अच्छा तरीका क्या है?


96

क्या एक "कम्प्यूटेशनल" त्वरित रूप से एक पुनरावृत्त की गिनती प्राप्त करने का तरीका है?

int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();

... सीपीयू चक्रों की बर्बादी की तरह लगता है।


2
जरूरी नहीं कि एक इटैलर "काउंट" के साथ किसी चीज़ के अनुरूप हो ...
ऑलिवर चार्ल्सवर्थ

Iterators वे क्या हैं; एक संग्रह की अगली वस्तु के लिए पुनरावृति (यह सेट, सरणी, आदि की तरह कुछ भी हो सकता है) उन्हें आकार को बताने की आवश्यकता क्यों है जब उन्हें परवाह नहीं है कि वे क्या करने की कोशिश कर रहे हैं? to provide an implementation-independent method for access, in which the user does not need to know whether the underlying implementation is some form of array or of linked list, and allows the user go through the collection without explicit indexing. p पेंगुइनin.ewu.edu/~trolfe/LinkedSort/Iterator.html
ecle

जवाबों:


67

यदि आपको बस पुनरावृति मिली है, तो आपको यही करना होगा - यह नहीं पता कि कितने आइटम्स को इटर्सेट पर छोड़ दिया गया है, इसलिए आप इसे उस परिणाम के लिए क्वेरी नहीं कर सकते। उपयोगिता विधियां हैं जो ऐसा करने के लिए प्रतीत होंगी (जैसे कि Iterators.size()अमरूद में), लेकिन नीचे वे लगभग एक ही ऑपरेशन कर रहे हैं।

हालांकि, कई पुनरावृत्तियां संग्रह से आती हैं, जिन्हें आप अक्सर उनके आकार के लिए क्वेरी कर सकते हैं। और अगर यह एक उपयोगकर्ता द्वारा बनाया गया वर्ग है जिसके लिए आपको इटेटर मिल रहा है, तो आप उस वर्ग पर एक आकार () विधि प्रदान कर सकते हैं।

संक्षेप में, उस स्थिति में जहां आपके पास केवल इटरेटर है तो कोई बेहतर तरीका नहीं है, लेकिन बहुत अधिक बार आपके पास अंतर्निहित संग्रह या ऑब्जेक्ट तक पहुंच नहीं है, जिससे आप सीधे आकार प्राप्त करने में सक्षम हो सकते हैं।


के साइड-इफ़ेक्ट से सावधान रहें Iterators.size(...)(नीचे अन्य टिप्पणियों में और जावा-डॉक में उल्लेख किया गया है): "पुनरावृत्ति करने वाले तत्वों की संख्या लौटाता है। इटरेटर को छोड़ दिया जाएगा: इसकी hasNext () विधि झूठी हो जाएगी।" इसका मतलब है, आप बाद में अब Iterator का उपयोग नहीं कर सकते। Lists.newArrayList(some_iterator);मदद कर सकता है।
माइकलक्रे

91

अमरूद पुस्तकालय का उपयोग :

int size = Iterators.size(iterator);

आंतरिक रूप से यह सिर्फ सभी तत्वों पर निर्भर करता है इसलिए इसकी सुविधा के लिए।


8
यह बहुत सुरुचिपूर्ण है। बस याद रखें कि आप अपने
ईटरेटर

1
यह "कम्प्यूटेशनल रूप से त्वरित" नहीं है, यह एक सुविधा विधि है जिसमें इट्रेटर के सेवन का अवांछित दुष्प्रभाव होता है।
जाक

क्या आप बता सकते हैं कि यह कैसे काम करता है? @Andrejs सूची <Tuple2 <string, Integer >> wordCountsWithGroupByKey = wordsPairRdd.groupByKey () .mapValues ​​(intIterable - Iterables.size (intIterable)) इकट्ठा करना (); System.out.println ("wordCountsWithGroupByKey:" + wordCountsWithGroupByKey); "Iterables.size (intIterable)?
आदित्य वर्मा

15

जब आप पुनरावृत्ति के अंत तक पहुँचते हैं तो आपका कोड आपको एक अपवाद देगा। तुम यह कर सकते थे:

int i = 0;
while(iterator.hasNext()) {
    i++;
    iterator.next();
}

यदि आपके पास अंतर्निहित संग्रह तक पहुंच है, तो आप कॉल कर पाएंगे coll.size()...

संपादित करें ठीक है आपने संशोधित किया है ...


यह कितना कारगर है? क्या होगा अगर पुनरावृत्ति एक लाख मानों की तरह है?
माइक्रो

4
@ मैक्रो तकनीकी रूप से एक पुनरावृत्त अनंत हो सकता है - जिस स्थिति में लूप हमेशा के लिए चला जाएगा।
assylias

12

आपको हमेशा इटरेट करना होगा। फिर भी आप जावा 8, 9 का उपयोग बिना खोज के लूपिंग के बिना गिनती करने के लिए कर सकते हैं:

Iterable<Integer> newIterable = () -> iter;
long count = StreamSupport.stream(newIterable.spliterator(), false).count();

यहाँ एक परीक्षण है:

public static void main(String[] args) throws IOException {
    Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4, 5).iterator();
    Iterable<Integer> newIterable = () -> iter;
    long count = StreamSupport.stream(newIterable.spliterator(), false).count();
    System.out.println(count);
}

यह प्रिंट:

5

दिलचस्प है कि आप parallelइस कॉल पर ध्वज को बदलकर यहां गिनती ऑपरेशन को समानांतर कर सकते हैं :

long count = StreamSupport.stream(newIterable.spliterator(), *true*).count();

8

अमरूद पुस्तकालय का उपयोग करते हुए , एक और विकल्प में परिवर्तित करने के Iterableलिए है List

List list = Lists.newArrayList(some_iterator);
int count = list.size();

यदि इसका आकार मिलने के बाद आपको पुनरावृति के तत्वों को एक्सेस करने की आवश्यकता है, तो इसका उपयोग करें। Iterators.size()आप का उपयोग करके अब iterated तत्वों तक पहुँच सकते हैं।


2
@LoveToCode मूल प्रश्न पर उदाहरण की तुलना में कम कुशल है
शीतकालीन

2
ज़रूर, सभी तत्वों के साथ एक नई वस्तु का निर्माण केवल पुनरावृत्ति और त्यागने की तुलना में धीमा है। IMHO, यह समाधान एक-लाइनर है जो कोड पठनीयता में सुधार करता है। मैं कुछ तत्वों (1000 तक) के साथ संग्रह के लिए इसका उपयोग करता हूं या जब गति कोई समस्या नहीं होती है।
tashuhka

7

यदि आपके पास सभी इट्रेटर हैं, तो नहीं, कोई "बेहतर" तरीका नहीं है। यदि पुनरावृत्ति एक संग्रह से आती है तो आप आकार के लिए ऐसा कर सकते हैं।

ध्यान रखें कि Iterator अलग-अलग मूल्यों को ट्रेस करने के लिए सिर्फ एक इंटरफ़ेस है, आपके पास इस तरह के कोड बहुत अच्छे होंगे

    new Iterator<Long>() {
        final Random r = new Random();
        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public Long next() {
            return r.nextLong();
        }

        @Override
        public void remove() {
            throw new IllegalArgumentException("Not implemented");
        }
    };

या

    new Iterator<BigInteger>() {
        BigInteger next = BigInteger.ZERO;

        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public BigInteger next() {
            BigInteger current = next;
            next = next.add(BigInteger.ONE);
            return current;
        }

        @Override
        public void remove() {
            throw new IllegalArgumentException("Not implemented");
        }
    }; 

4

कोई और अधिक कुशल तरीका नहीं है, अगर आपके पास सब कुछ है। और अगर इटरेटर का उपयोग केवल एक बार किया जा सकता है, तो इटरेटर की सामग्री प्राप्त करने से पहले गिनती प्राप्त करना ... समस्याग्रस्त है।

समाधान या तो आपके आवेदन को बदलने के लिए है ताकि इसे गिनती की आवश्यकता न हो, या किसी अन्य माध्यम से गणना प्राप्त करने के लिए। (उदाहरण के लिए, पास करने के Collectionबजाय Iterator...)


0

के लिए जावा 8 आप इस्तेमाल कर सकते हैं,

public static int getIteratorSize(Iterator iterator){
        AtomicInteger count = new AtomicInteger(0);
        iterator.forEachRemaining(element -> {
            count.incrementAndGet();
        });
        return count.get();
    }

-5

इटरेटर ऑब्जेक्ट में आपके संग्रह में शामिल तत्वों की समान संख्या होती है।

List<E> a =...;
Iterator<E> i = a.iterator();
int size = a.size();//Because iterators size is equal to list a's size.

लेकिन बजाय इटरेटर के आकार हो रही है और है कि आकार के सूचकांक 0 के माध्यम से पुनरावृत्ति की, यह पुनरावृति करने के लिए बेहतर विधि के माध्यम से है अगले () इटरेटर की।


क्या होगा अगर हमारे पास नहीं है a, लेकिन केवल i?
Tvde1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.