2009-10-24 10 views
7

पर एक लिस्ट इटरेटर को सीमित करें List की शुरुआत से अधिकांश एन तत्वों पर लौटने वाले इटरेटर को प्राप्त करने का एक आसान और तेज़ तरीका क्या है?पहले एन तत्वों (अनुकूलित)

सरल संस्करणों मैं के साथ आ सकता है:

# 1:

import com.google.common.collect.Iterators; 

// ... 

public static <E> Iterator<E> lengthLimitedIterator(Iterable<E> source, int maxLen) { 
    return Iterators.partition(source.iterator(), maxLen).next().iterator(); 
} 

# 2:

public static <E> Iterator<E> lengthLimitedIterator(List<E> source, int maxLen) { 
    return source.subList(0, Math.min(source.size(), maxLen)).iterator(); 
} 

दुर्भाग्य से दोनों संस्करणों एक अस्थायी List जो काफी के रूप में प्रदर्शन को प्रभावित करता बनाने मैं इस विधि को एक तंग लूप में लाखों बार बुला रहा हूं।

क्या कोई अन्य लाइब्रेरी फ़ंक्शन है जिसके लिए मैं इसका उपयोग कर सकता हूं?


नोट: मैं सूची पर पुनरावृत्ति के रूप में मैं यह एक तरीका है जो अपने तर्क के रूप में पुनरावर्तक लेता है गुजर रहा से बचने नहीं कर सकते हैं और मुझे लगता है कि वर्ग संशोधित नहीं कर सकते। अपने डेकोरेटर गिनती, जो next() द्वारा वृद्धि की जाती है, और नियंत्रण hasNext() द्वारा प्रयोग किया जाता रहता है:

उत्तर

8

लगता है के रूप में यदि feature बीटा में अमरूद, वर्तमान में जोड़ दिया जाएगा (r06 के रूप में):

public static <T> Iterator<T> limit(Iterator<T> iterator, int limitSize) 
+1

'Iterators' के अलावा, ध्यान दें कि [' Iterables' की सीमा भी है() 'विधि] (http: //docs.guava- libraries.googlecode.com/git/javadoc/com/google/common/collect/Iterables.html#limit(java.lang.Iterable,%20int))। तो यदि आपके पास 'सूची' है, तो 'Iterables.limit (aist, 3)' करना सबसे आसान है। – Jonik

5

यह एक जगह है जहाँ एक Decorator बहुत अच्छी तरह से काम करता है है।

उदाहरण (जानबूझकर अधूरा):

public class LengthLimitedIterator<T> 
implements Iterator<T> 
{ 
    private Iterator<T> _wrapped; 
    private int _length; 
    private int _count; 

    public LengthLimitedIterator(Iterator<T> wrapped, int length) 
    { 
     _wrapped = wrapped; 
     _length = length; 
    } 


    public boolean hasNext() 
    { 
     if (_count < _length) 
      return _wrapped.hasNext(); 
     return false; 
    } 

    public T next() 
    { 
     // FIXME - add exception if count >= length 
     _count++; 
     return _wrapped.next(); 
    } 
5

क्यों नहीं बस

list.subList(0, 42).iterator(); 

मैं नहीं यकीन है कि आपको लगता है कि अस्थायी सूची के निर्माण के बारे में क्यों बात नहीं कर रहा हूँ। यह कुछ भी नहीं करता जो मैं महंगा मानता हूं। असल में, इस सूची को बनाने से कहीं अधिक सस्ता है, जो मुझे लगता है कि आप करते हैं।

+0

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

14

आप पहले ही जानते हैं कि यह एक सूची है, इसलिए आप केवल List.subList(int fromIndex, int toIndex) विधि पर कॉल कर सकते हैं। विनिर्देश के अनुसार, उपसूची को मूल सूची द्वारा समर्थित किया जाता है, इसलिए यह वास्तव में एक पूर्ण उड़ा List नहीं बना रहा है, बस किसी प्रकार का प्रॉक्सी ऑब्जेक्ट।

+0

समस्या यह है कि आपको यह सुनिश्चित करना है कि आपको यह सुनिश्चित करना है सूची में पर्याप्त उपलब्ध वस्तुएं हैं, या आपको 'इंडेक्सऑटऑफबाउंड एक्सेप्शन' मिलेगा। मुझे नहीं पता कि यह सीमा अन्य प्रस्तावित समाधानों में भी मौजूद है, लेकिन यह होगा कि अधिकांश_ n तत्वों को पुन: स्थापित करने के लिए एक बिल्टिन विकल्प होना अच्छा लगेगा। – Itai

0

इस संस्करण में पता चला है अन्य उदाहरण में से किसी की तुलना में तेजी होने के लिए:

public static <E> Iterator<E> lengthLimitedIterator(List<E> source, int maxLen) { 
    maxLen = Math.min(maxLen, source.size()); 
    ArrayList<E> tempList = new ArrayList<E>(maxLen); 
    for (int i = 0; i < maxLen; ++ i) { 
     tempList.add(source.get(i)); 
    } 
    return tempList.iterator(); 
} 

अस्थायी सूची वैसे भी बनाया जाना है, तो एक ArrayList अन्य पुस्तकालय तरीकों से लौटे सजाया सूचियों की तुलना में तेजी है।

मेरा अनुमान है कि ArrayList वीएम के भीतर कुछ विशेष उपचार प्राप्त कर रहा है।

हो सकता है कि यह बहुत ही लंबी सूची के लिए अक्षम हो सकता है, लेकिन मेरे सूचियों कम हैं (लगभग हमेशा 50 से कम तत्वों।)

+0

संयोग से, मैं आपके "यह उससे तेज है" निष्कर्षों से सावधान हूं, क्योंकि जावा में माइक्रोबेंमार्किंग बहुत है, बहुत त्रुटि-प्रवण है। एक भ्रामक परिणाम प्राप्त करने के सौ तरीके हैं। मुझे सच में लगता है कि आपको स्वच्छ उपसूची()। Iterator() समाधान के साथ चिपकने का प्रयास करना चाहिए। –

+0

@ केविन, मैंने इसे वास्तविक एप्लिकेशन में माप लिया है जिसका मैं उपयोग कर रहा हूं। मैं दावा नहीं कर रहा हूं कि यह सामान्य मामले में तेज़ है। – finnw

1

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

2

ArrayList.sublist(int,int) विधि मूल सूची की प्रति नहीं बनाती है। इसके बजाय यह एक सबलिस्ट उदाहरण देता है जो मूल ऐरेलिस्ट को लपेटता है। ऐरे से व्युत्पन्न उपन्यासकार द्वारा लौटाया गया इटरेटर एक प्रतिलिपि नहीं बनाता है।

तो मेरी सलाह है कि आप अपनी आधार सूची प्रकार और sublist विधि के रूप में ArrayList का उपयोग करने का प्रयास करें। यदि यह पर्याप्त तेज़ नहीं है, तो ArrayList का अपना संस्करण लागू करें जो limitedLengthIterator विधि लागू करता है। उदाहरण के लिए, आप उस कोड से छुटकारा पाने में सक्षम होना चाहिए जो समवर्ती संशोधन के लिए जांच करता है।

+0

लेकिन रैपर वास्तव में मूल ArrayList – finnw

+0

@finnw से धीमा है - लेकिन यह सूची की प्रतिलिपि बनाने से तेज़ होना चाहिए। –

+0

निर्भर करता है कि इसे कितनी बार पुनरावृत्त किया जाता है। – finnw

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