क्या जावा के प्रत्येक लूप में एक पुनरावृत्ति-काउंटर तक पहुंचने का एक तरीका है?


273

क्या जावा के प्रत्येक लूप में एक तरीका है

for(String s : stringArray) {
  doSomethingWith(s);
}

यह पता लगाने के लिए कि लूप को कितनी बार संसाधित किया जा चुका है?

पुराने और प्रसिद्ध for(int i=0; i < boundary; i++)- पाश का उपयोग करने के अलावा , निर्माण है

int i = 0;
for(String s : stringArray) {
  doSomethingWith(s);
  i++;
}

इस तरह के एक काउंटर के लिए एक ही रास्ता उपलब्ध है प्रत्येक लूप में?


2
एक और अफ़सोस की बात है कि आप लूप के बाहर लूप चर का उपयोग नहीं कर सकते हैं,Type var = null; for (var : set) dosomething; if (var != null) then ...
वैल

@Val जब तक संदर्भ प्रभावी अंतिम नहीं है। इस सुविधा का उपयोग करने के लिए मेरा जवाब देखें
rmuller

जवाबों:


205

नहीं, लेकिन आप अपना स्वयं का काउंटर प्रदान कर सकते हैं।

इसका कारण यह है कि प्रत्येक लूप आंतरिक रूप से एक काउंटर नहीं है ; यह Iterable इंटरफ़ेस पर आधारित है, अर्थात यह Iterator"संग्रह" के माध्यम से एक लूप का उपयोग करता है - जो कि बिल्कुल भी संग्रह नहीं हो सकता है, और वास्तव में अनुक्रमणिका (जैसे कि एक लिंक की गई सूची) के आधार पर कुछ नहीं हो सकता है।


5
रूबी के पास इसके लिए एक निर्माण है और जावा को भी इसे प्राप्त करना चाहिए ...for(int idx=0, String s; s : stringArray; ++idx) doSomethingWith(s, idx);
निकोलस डिपियाज़ा

9
जवाब "नहीं, लेकिन आप अपने खुद के काउंटर प्रदान कर सकते हैं।"
user1094206

1
FYI करें @NicholasDiPiazza रूबी में एक each_with_indexलूप विधि है Enumerable। Apidock.com/ruby/Enumerable/each_with_index देखें
Saywhatnow

@saywhatnow हाँ, इसका मतलब है कि मुझे खेद है - यकीन नहीं कि मैं धूम्रपान कर रहा था जब मैंने पिछली टिप्पणी की थी
निकोलस डिपियाज़ा

2
"इसका कारण यह है कि प्रत्येक लूप आंतरिक रूप से एक काउंटर नहीं है"। के रूप में पढ़ा जाना चाहिए "जावा डेवलपर्स ने प्रोग्रामर को इंडेक्स वैरिएबल को forलूप के अंदर प्रारंभिक मूल्य के साथ निर्दिष्ट करने की परवाह नहीं की ", कुछ इस तरहfor (int i = 0; String s: stringArray; ++i)
izogfif

64

एक और तरीका है।

यह देखते हुए कि आप अपनी खुद की Indexकक्षा और एक स्थिर विधि लिखते हैं Iterableजो इस वर्ग के एक से अधिक उदाहरण देता है जो आप कर सकते हैं

for (Index<String> each: With.index(stringArray)) {
    each.value;
    each.index;
    ...
}

जहां का कार्यान्वयन With.indexकुछ इस तरह है

class With {
    public static <T> Iterable<Index<T>> index(final T[] array) {
        return new Iterable<Index<T>>() {
            public Iterator<Index<T>> iterator() {
                return new Iterator<Index<T>>() {
                    index = 0;
                    public boolean hasNext() { return index < array.size }
                    public Index<T> next() { return new Index(array[index], index++); }
                    ...
                }
            }
        }
    }
}

7
नीच विचार। मुझे लगता है कि यह इंडेक्स क्लास के अल्पकालिक ऑब्जेक्ट निर्माण के लिए नहीं होगा।
mR_fr0g

3
@ mR_fr0g चिंता न करें, मैंने इसे बेंचमार्क किया और इन सभी वस्तुओं को बनाने से प्रत्येक पुनरावृत्ति के लिए एक ही वस्तु का पुन: उपयोग करने की तुलना में कोई धीमा नहीं है। कारण यह है कि इन सभी वस्तुओं को केवल एडेन स्पेस में आवंटित किया गया है और ढेर तक पहुंचने के लिए जीवन भर कभी नहीं। इसलिए उन्हें आवंटित करना उतना ही तेज़ है जितना कि स्थानीय चर आवंटित करना।
अकुंन

1
@akuhn रुको। ईडन स्पेस का मतलब यह नहीं है कि कोई भी जीसी नहीं है। इसके विपरीत, आपको निर्माणकर्ता को आमंत्रित करना होगा, जीसी के साथ जल्द ही स्कैन करना होगा और अंतिम रूप देना होगा। यह न केवल सीपीयू को लोड करता है, बल्कि हर समय कैश को अमान्य करता है। स्थानीय चरों के लिए ऐसा कुछ भी आवश्यक नहीं है। आप क्यों कहते हैं कि यह "वही" है?
वैल

7
यदि आप इस तरह की छोटी जीवित वस्तुओं के प्रदर्शन के बारे में चिंतित हैं, तो आप इसे गलत कर रहे हैं। प्रदर्शन के बारे में चिंता करने के लिए सबसे बड़ी बात होनी चाहिए ... पहले पठनीयता। यह वास्तव में एक बहुत अच्छा निर्माण है।
बिल के

4
मैं कहने जा रहा था कि मैं वास्तव में बहस की आवश्यकता को नहीं समझता जब सूचकांक उदाहरण एक बार बनाया जा सकता है और पुन: उपयोग / अद्यतन किया जा सकता है, बस तर्क को लूटने और सभी को खुश करने के लिए। हालाँकि, मेरे माप में, जो संस्करण एक नया सूचकांक बनाता है () हर बार मेरी मशीन पर दो बार से अधिक तेजी से प्रदर्शन किया, लगभग एक ही पुनरावृत्तियों के समान चलने वाले पुनरावृत्तियों के बराबर।
एरिक वुड्रूफ़

47

सबसे आसान उपाय यह है कि आप अपना काउंटर इस प्रकार चलाएं:

int i = 0;
for (String s : stringArray) {
    doSomethingWith(s, i);
    i++;
}

इसका कारण यह है कि कोई भी वास्तविक गारंटी नहीं है कि एक संग्रह में आइटम (जो कि उस पर forचलने वाला संस्करण है ) यहां तक कि एक सूचकांक भी है, या यहां तक ​​कि एक परिभाषित आदेश भी है (कुछ संग्रह जब आप तत्वों को जोड़ते या हटाते हैं तो क्रम बदल सकते हैं)।

उदाहरण के लिए, निम्न कोड देखें:

import java.util.*;

public class TestApp {
  public static void AddAndDump(AbstractSet<String> set, String str) {
    System.out.println("Adding [" + str + "]");
    set.add(str);
    int i = 0;
    for(String s : set) {
        System.out.println("   " + i + ": " + s);
        i++;
    }
  }

  public static void main(String[] args) {
    AbstractSet<String> coll = new HashSet<String>();
    AddAndDump(coll, "Hello");
    AddAndDump(coll, "My");
    AddAndDump(coll, "Name");
    AddAndDump(coll, "Is");
    AddAndDump(coll, "Pax");
  }
}

जब आप उसे चलाते हैं, तो आप कुछ इस तरह देख सकते हैं:

Adding [Hello]
   0: Hello
Adding [My]
   0: Hello
   1: My
Adding [Name]
   0: Hello
   1: My
   2: Name
Adding [Is]
   0: Hello
   1: Is
   2: My
   3: Name
Adding [Pax]
   0: Hello
   1: Pax
   2: Is
   3: My
   4: Name

यह दर्शाता है कि, ठीक है, आदेश को एक सेट की मुख्य विशेषता नहीं माना जाता है।

मैनुअल काउंटर के बिना इसे करने के अन्य तरीके हैं लेकिन यह संदिग्ध लाभ के लिए बहुत ही उचित काम है।


2
यह अभी भी सूची और Iterable इंटरफेस के साथ, सबसे स्पष्ट समाधान प्रतीत होता है।
यहोशू पिंजर

27

जावा 8 में लैम्ब्डा और कार्यात्मक इंटरफेस का उपयोग करना नए लूप एब्स्ट्रैक्ट को संभव बनाता है। मैं सूचकांक और संग्रह आकार के साथ एक संग्रह पर लूप कर सकता हूं:

List<String> strings = Arrays.asList("one", "two","three","four");
forEach(strings, (x, i, n) -> System.out.println("" + (i+1) + "/"+n+": " + x));

कौन से आउटपुट:

1/4: one
2/4: two
3/4: three
4/4: four

जिसे मैंने इस प्रकार लागू किया है:

   @FunctionalInterface
   public interface LoopWithIndexAndSizeConsumer<T> {
       void accept(T t, int i, int n);
   }
   public static <T> void forEach(Collection<T> collection,
                                  LoopWithIndexAndSizeConsumer<T> consumer) {
      int index = 0;
      for (T object : collection){
         consumer.accept(object, index++, collection.size());
      }
   }

संभावनाएं अनंत हैं। उदाहरण के लिए, मैं एक अमूर्तता का निर्माण करता हूं जो पहले तत्व के लिए एक विशेष फ़ंक्शन का उपयोग करता है:

forEachHeadTail(strings, 
                (head) -> System.out.print(head), 
                (tail) -> System.out.print(","+tail));

कौन सा अल्पविराम से अलग की गई सूची को सही ढंग से प्रिंट करता है:

one,two,three,four

जिसे मैंने इस प्रकार लागू किया है:

public static <T> void forEachHeadTail(Collection<T> collection, 
                                       Consumer<T> headFunc, 
                                       Consumer<T> tailFunc) {
   int index = 0;
   for (T object : collection){
      if (index++ == 0){
         headFunc.accept(object);
      }
      else{
         tailFunc.accept(object);
      }
   }
}

इस प्रकार की चीजों को करने के लिए पुस्तकालय पॉप अप करने लगेंगे, या आप अपना रोल कर सकते हैं।


3
पोस्ट की आलोचना नहीं है (यह "इन दिनों मुझे लगता है कि ऐसा करने का सबसे अच्छा तरीका है"), लेकिन मैं यह देखने के लिए संघर्ष करता हूं कि लूप के लिए एक साधारण पुराने स्कूल की तुलना में यह कितना आसान / बेहतर है: (इंट i = 0; मैं <; list.size (); i ++) {} यहां तक ​​कि दादी भी इसे समझ सकती हैं और शायद सिंटैक्स और असामान्य पात्रों के बिना टाइप करना आसान होता है, जो लैम्बडा उपयोग करता है। मुझे गलत मत समझो, मुझे कुछ चीजों के लिए लैम्ब्डा का उपयोग करना पसंद है (कॉलबैक / इवेंट हैंडलर प्रकार का पैटर्न) लेकिन मैं इस तरह के मामलों में उपयोग को समझ नहीं सकता। महान उपकरण, लेकिन हर समय इसका उपयोग करते हुए , मैं अभी नहीं कर सकता।
मैनियस

मुझे लगता है, ऑफ-बाय-वन इंडेक्स के कुछ परिहार से बचने के लिए / सूची के खिलाफ ही कम। लेकिन ऊपर पोस्ट विकल्प है: int i = 0; for (स्ट्रिंग s: stringArray) {doSomethingWith (s, i); मैं ++; }
मैनियस

21

जावा 8 ने Iterable#forEach()/ Map#forEach()विधि पेश की , जो प्रत्येक लूप के लिए "शास्त्रीय" की तुलना में कई Collection/ Mapकार्यान्वयन के लिए अधिक कुशल है । हालांकि, इस मामले में भी एक सूचकांक प्रदान नहीं किया गया है। यहां ट्रिक AtomicIntegerलैम्ब्डा एक्सप्रेशन के बाहर उपयोग करने की है । नोट: लैम्ब्डा अभिव्यक्ति के भीतर उपयोग किए जाने वाले चर प्रभावी रूप से अंतिम होने चाहिए, यही कारण है कि हम एक साधारण का उपयोग नहीं कर सकते हैं int

final AtomicInteger indexHolder = new AtomicInteger();
map.forEach((k, v) -> {
    final int index = indexHolder.getAndIncrement();
    // use the index
});

16

मुझे डर है कि यह संभव नहीं है foreach। लेकिन मैं आपको एक सरल पुराने ढंग के लूप के लिए सुझाव दे सकता हूं :

    List<String> l = new ArrayList<String>();

    l.add("a");
    l.add("b");
    l.add("c");
    l.add("d");

    // the array
    String[] array = new String[l.size()];

    for(ListIterator<String> it =l.listIterator(); it.hasNext() ;)
    {
        array[it.nextIndex()] = it.next();
    }

ध्यान दें कि, सूची इंटरफ़ेस आपको पहुँच प्रदान करता है it.nextIndex()

(संपादित करें)

अपने बदले हुए उदाहरण के लिए:

    for(ListIterator<String> it =l.listIterator(); it.hasNext() ;)
    {
        int i = it.nextIndex();
        doSomethingWith(it.next(), i);
    }

9

परिवर्तनों में Sunसे एक के लिए विचार कर रहा Java7है कि Iteratorफॉरच लूप में आंतरिक तक पहुंच प्रदान करना है । सिंटेक्स कुछ इस तरह होगा (यदि यह स्वीकार किया जाता है):

for (String str : list : it) {
  if (str.length() > 100) {
    it.remove();
  }
}

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


7

मुहावरेदार समाधान:

final Set<Double> doubles; // boilerplate
final Iterator<Double> iterator = doubles.iterator();
for (int ordinal = 0; iterator.hasNext(); ordinal++)
{
    System.out.printf("%d:%f",ordinal,iterator.next());
    System.out.println();
}

यह वास्तव में समाधान है कि Google ने अमरूद चर्चा में सुझाव दिया कि उन्होंने क्यों प्रदान नहीं किया CountingIterator


4

हालाँकि, इसे प्राप्त करने के लिए कई अन्य तरीके हैं, मैं कुछ असंतुष्ट उपयोगकर्ताओं के लिए अपना रास्ता साझा करूँगा। मैं Java 8 IntStream फीचर का उपयोग कर रहा हूं।

1. अर्र

Object[] obj = {1,2,3,4,5,6,7};
IntStream.range(0, obj.length).forEach(index-> {
    System.out.println("index: " + index);
    System.out.println("value: " + obj[index]);
});

2. सूची

List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");

IntStream.range(0, strings.size()).forEach(index-> {
    System.out.println("index: " + index);
    System.out.println("value: " + strings.get(index));
});

2

यदि आपको प्रत्येक लूप के लिए एक काउंटर की आवश्यकता है तो आपको अपने आप को गिनना होगा। जहाँ तक मुझे पता है, वहाँ कोई काउंटर नहीं बनाया गया है।


(मैंने सवाल में उस बग को ठीक कर दिया है।)
टॉम हैटिन -

1

पैक्स के उत्तर के लिए "वैरिएंट" है ... ;-)

int i = -1;
for(String s : stringArray) {
    doSomethingWith(s, ++i);
}

3
जिज्ञासु, वहाँ पर इस का उपयोग करने का कोई लाभ है, प्रतीत होता है, स्पष्ट i=0; i++;दृष्टिकोण?
यहोशू पिंजर

1
मुझे लगता है कि अगर आपको गुंजाइश के लिए doSomething के बाद फिर से i इंडेक्स का उपयोग करने की आवश्यकता है।
गेडो

1

उन परिस्थितियों के लिए जहां मुझे केवल कभी-कभी सूचकांक की आवश्यकता होती है, जैसे कि एक पकड़ क्लॉज़ में, मैं कभी-कभी indexOf का उपयोग करूंगा।

for(String s : stringArray) {
  try {
    doSomethingWith(s);
  } catch (Exception e) {
    LOGGER.warn("Had some kind of problem with string " +
      stringArray.indexOf(s) + ": " + s, e);
  }
}

2
सावधान रहें कि इसके लिए (। असमान) (- एरेस ऑब्जेक्ट्स के कार्यान्वयन की आवश्यकता है, जो किसी विशिष्ट वस्तु की विशिष्ट पहचान कर सकें। यह वह जगह है नहीं स्ट्रिंग्स के लिए मामला है, अगर एक निश्चित स्ट्रिंग कई बार सरणी में है यदि आप केवल प्रथम घटना के सूचकांक मिल जाएगा, भले ही आप पहले से ही एक ही तार के साथ एक बाद की मद पर पुनरावृत्ति कर रहे थे।
कोसी 2801

-1

सबसे अच्छा और अनुकूलित समाधान निम्नलिखित कार्य करना है:

int i=0;

for(Type t: types) {
  ......
  i++;
}

जहाँ प्रकार कोई भी डेटा प्रकार हो सकता है और प्रकार वह चर है जिस पर आप लूप के लिए आवेदन कर रहे हैं।


कृपया अपना उत्तर एक प्रतिलिपि प्रस्तुत करने योग्य कोड प्रारूप में प्रदान करें।
नरेमन दरविश

यह ठीक उसी तरह है जिसके लिए एक वैकल्पिक समाधान चाहिए था। प्रश्न प्रकारों के बारे में नहीं है, बल्कि मैन्युअल रूप से गिनने की तुलना में अलग तरीके से लूप काउंटर तक पहुंचने की संभावनाओं के बारे में है।
कोसी 2801

-4

मैं थोड़ा हैरान हूं कि किसी ने निम्नलिखित का सुझाव नहीं दिया (मैं मानता हूं कि यह एक आलसी दृष्टिकोण है ...); यदि stringArray किसी प्रकार की एक सूची है, तो आप मौजूदा गणना के लिए मान वापस करने के लिए stringArray.indexOf (S) जैसे कुछ का उपयोग कर सकते हैं।

नोट: यह मान लिया गया है कि सूची के तत्व अद्वितीय हैं, या यह कि यह कोई फर्क नहीं पड़ता कि वे गैर-अद्वितीय हैं (क्योंकि उस स्थिति में यह पहली प्रतिलिपि के सूचकांक को वापस मिल जाएगा)।

ऐसी स्थितियां हैं जिनमें पर्याप्त होगा ...


9
पूरे पाश के लिए O (n²) के पास एक प्रदर्शन के साथ कुछ स्थितियों की कल्पना करना बहुत कठिन है जहां यह किसी और चीज से बेहतर होगा। माफ़ करना।
कोसी 2801 21

-5

यहाँ एक उदाहरण है कि मैंने यह कैसे किया। यह प्रत्येक लूप के लिए इंडेक्स प्राप्त करता है। उम्मीद है की यह मदद करेगा।

public class CheckForEachLoop {

    public static void main(String[] args) {

        String[] months = new String[] { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST",
                "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" };
        for (String s : months) {
            if (s == months[2]) { // location where you can change
              doSomethingWith(s); // however many times s and months
                                  // doSomethingWith(s) will be completed and 
                                  // added together instead of counter
            }

        }
        System.out.println(s); 


    }
}

1
क्षमा करें, यह प्रश्न का उत्तर नहीं दे रहा है। यह सामग्री तक पहुँचने के बारे में नहीं है, बल्कि एक काउंटर के बारे में है कि लूप कितनी बार पहले से ही पुनरावृत्त हो चुका है।
कोसी 2801

प्रश्न के लिए प्रत्येक शैली लूप में लूप में वर्तमान सूचकांक का पता लगाना था।
Rumman0786
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.