आकार-सीमित कतार जो जावा में अंतिम N तत्व रखती है


197

जावा पुस्तकालयों पर एक बहुत ही सरल और त्वरित प्रश्न: क्या एक तैयार वर्ग है जो Queueएक निश्चित अधिकतम आकार के साथ लागू होता है - अर्थात यह हमेशा तत्वों को जोड़ने की अनुमति देता है, लेकिन यह चुपचाप नए जोड़े गए तत्वों के लिए अंतरिक्ष को समायोजित करने के लिए सिर के तत्वों को हटा देगा।

बेशक, इसे मैन्युअल रूप से लागू करना तुच्छ है:

import java.util.LinkedList;

public class LimitedQueue<E> extends LinkedList<E> {
    private int limit;

    public LimitedQueue(int limit) {
        this.limit = limit;
    }

    @Override
    public boolean add(E o) {
        super.add(o);
        while (size() > limit) { super.remove(); }
        return true;
    }
}

जहाँ तक मैं देख रहा हूँ, जावा stdlibs में कोई मानक कार्यान्वयन नहीं है, लेकिन अपाचे कॉमन्स में एक या ऐसा कुछ हो सकता है?



9
@ केविन: आप ऐसे चिढ़ते हैं।
मार्क पीटर्स

5
यदि मैं इस पुस्तकालय का एकमात्र उपयोग करूंगा तो मैं एक और पुस्तकालय का परिचय नहीं
दूंगा

2
@ ऑवरराइड सार्वजनिक बूलियन ऐड (प्रोपेगैशनटैस्क टी) {बूलियन जोड़ा = super.add (टी); जबकि (जोड़ा गया && आकार) ()> सीमा) {super.remove (); } रिटर्न जोड़ा; }
रेनॉड

6
चेतावनी: प्रश्न में कोड, हालांकि यह स्पष्ट रूप से काम करता है, यह बैकफ़ायर कर सकता है। अतिरिक्त तरीके हैं जो कतार में और अधिक तत्व जोड़ सकते हैं (जैसे कि AddAll ()) जो इस आकार की जांच को अनदेखा करते हैं। अधिक जानकारी के लिए प्रभावी जावा 2 संस्करण देखें - आइटम 16: वंशानुक्रम पर अनुकूल रचना
डिएगो

जवाबों:


171

Apache commons collection 4 में एक CircularFifoQueue <> है जिसे आप ढूंढ रहे हैं। जावदोक का उद्धरण:

CircularFifoQueue एक निश्चित आकार के साथ पहली-पहली पहली कतार में है जो पूर्ण होने पर अपने सबसे पुराने तत्व को बदल देता है।

    import java.util.Queue;
    import org.apache.commons.collections4.queue.CircularFifoQueue;

    Queue<Integer> fifo = new CircularFifoQueue<Integer>(2);
    fifo.add(1);
    fifo.add(2);
    fifo.add(3);
    System.out.println(fifo);

    // Observe the result: 
    // [2, 3]

यदि आप अपाचे कॉमन्स संग्रह (3.x) के पुराने संस्करण का उपयोग कर रहे हैं, तो आप सर्कुलर फ़िफ़बोफ़र का उपयोग कर सकते हैं जो मूल रूप से जेनरिक के बिना एक ही बात है।

अद्यतन : अद्यतन उत्तर कॉमन्स संग्रह 4 की रिलीज़ के बाद जो कि जेनरिक का समर्थन करता है।


1
यह एक अच्छा उम्मीदवार है, लेकिन, अफसोस, यह जेनेरिक का उपयोग नहीं करता है :(
ग्रेकैट

धन्यवाद! लगता है कि यह अब के लिए सबसे व्यवहार्य विकल्प है :)
ग्रेस्कैट

3
2013-10 के आसपास Google Guava संस्करण 15 में जोड़े जाने वाले लिंक के लिए यह अन्य उत्तर देखें । EvictingQueue
बेसिल बॉर्क

क्या कोई कॉलबैक कहा जाता है जब पूर्ण कतार के अलावा तत्व को कतार से बाहर निकाल दिया जाता है?
ed22

एक "परिपत्र कतार" केवल एक कार्यान्वयन है जो प्रश्न को संतुष्ट करता है। लेकिन सवाल सीधे तौर पर एक परिपत्र कतार के मुख्य अंतर से लाभ नहीं होता है, अर्थात प्रत्येक बाल्टी को प्रत्येक अतिरिक्त / विलोपन से मुक्त / पुनः प्राप्त नहीं करना है।
1717

90

अमरूद में अब एक एविसीक्यूक्यू है , एक गैर-अवरुद्ध कतार है जो कतार में नए तत्वों को जोड़ने का प्रयास करते समय स्वचालित रूप से कतार के सिर से तत्वों को निकालता है और यह पूर्ण है।

import java.util.Queue;
import com.google.common.collect.EvictingQueue;

Queue<Integer> fifo = EvictingQueue.create(2); 
fifo.add(1); 
fifo.add(2); 
fifo.add(3); 
System.out.println(fifo); 

// Observe the result: 
// [2, 3]

आधिकारिक तौर पर सामने आने के बाद इसे इस्तेमाल करना दिलचस्प होना चाहिए।
आसफ

यहाँ स्रोत है: code.google.com/p/guava-lbooks/source/browse/guava/src/com/… - - ऐसा लगता है कि अमरूद की वर्तमान रिलीज़ के साथ कॉपी और संकलन करना आसान होगा
टॉम करचरा

1
अद्यतन: इस वर्ग को आधिकारिक तौर पर 2013-10 के आसपास संस्करण 15 में Google अमरूद के साथ जारी किया गया था ।
बेसिल बॉर्क

1
@MaciejMiklas सवाल एक FIFO के लिए पूछता है, EvictingQueueएक FIFO है। यदि कोई संदेह है, तो इस कार्यक्रम का प्रयास करें: Queue<Integer> fifo = EvictingQueue.create(2); fifo.add(1); fifo.add(2); fifo.add(3); System.out.println(fifo); परिणाम का निरीक्षण करें:[2, 3]
kostmo

2
यह अब सही उत्तर है। दस्तावेज़ीकरण से इसका थोड़ा अस्पष्ट है, लेकिन एवेकिंगक्यू एक फीफो है।
माइकल बॉकलिंग 15

11

मुझे @FractalizeR समाधान पसंद है। लेकिन मैं इसके अलावा Super.add (o) से वैल्यू रखता हूँ और वापस करूँगा!

public class LimitedQueue<E> extends LinkedList<E> {

    private int limit;

    public LimitedQueue(int limit) {
        this.limit = limit;
    }

    @Override
    public boolean add(E o) {
        boolean added = super.add(o);
        while (added && size() > limit) {
           super.remove();
        }
        return added;
    }
}

1
जहाँ तक मैं देख सकता हूँ, FractalizeR ने कोई समाधान नहीं दिया है, केवल प्रश्न को संपादित किया है। प्रश्न के भीतर "समाधान" एक समाधान नहीं है, क्योंकि सवाल मानक या अर्ध-मानक पुस्तकालय में कुछ वर्ग का उपयोग करने के बारे में था, अपने स्वयं के रोलिंग के लिए नहीं।
ग्रेकट

3
यह ध्यान दिया जाना चाहिए कि यह समाधान थ्रेड-सुरक्षित नहीं है
कोनराड मोरावस्की

7
@KonradMorawski पूरे लिंक्डलिस्ट वर्ग वैसे भी थ्रेड-सुरक्षित नहीं है, इसलिए आपकी टिप्पणी इस संदर्भ में व्यर्थ है!
रेनॉड

@RenaudBlue थ्रेड सुरक्षा एक वैध चिंता है (यदि अक्सर अनदेखी की गई है), तो मुझे नहीं लगता कि टिप्पणी व्यर्थ है। और यह याद दिलाना कि LinkedListथ्रेड सुरक्षित नहीं है या तो निरर्थक नहीं होगा। इस प्रश्न के संदर्भ में, ओपी की विशिष्ट आवश्यकता यह विशेष रूप से महत्वपूर्ण बनाती है कि एक वस्तु को जोड़ना एक परमाणु ऑपरेशन के रूप में किया जाता है। दूसरे शब्दों में, नियमित लिंक्डलिस्ट के मामले में परमाणुता सुनिश्चित नहीं करने का जोखिम अधिक होगा।
कोनराड मोरावस्की

4
जैसे ही कोई कॉल करता है तो ब्रेक लेता है add(int,E)। और क्या addAllउद्देश्य के अनुसार काम करता है, अनिर्दिष्ट कार्यान्वयन विवरण पर निर्भर करता है। यही कारण है कि आप विरासत से अधिक प्रतिनिधिमंडल को प्राथमिकता देनी चाहिए ... है
होल्गर

6

रचना का उपयोग न करें (हां मेरा मतलब है कि विस्तार होता है, जैसा कि जावा में फैले कीवर्ड के संदर्भ में है और हां यह उत्तराधिकार है)। रचना सुपरियर है क्योंकि यह आपके कार्यान्वयन को पूरी तरह से ढाल देती है, जिससे आप अपने वर्ग के उपयोगकर्ताओं को प्रभावित किए बिना कार्यान्वयन को बदल सकते हैं।

मैं कुछ इस तरह की कोशिश करने की सलाह देता हूं (मैं सीधे इस विंडो में टाइप कर रहा हूं, इसलिए खरीदार सिंटैक्स त्रुटियों से सावधान रहें):

public LimitedSizeQueue implements Queue
{
  private int maxSize;
  private LinkedList storageArea;

  public LimitedSizeQueue(final int maxSize)
  {
    this.maxSize = maxSize;
    storageArea = new LinkedList();
  }

  public boolean offer(ElementType element)
  {
    if (storageArea.size() < maxSize)
    {
      storageArea.addFirst(element);
    }
    else
    {
      ... remove last element;
      storageArea.addFirst(element);
    }
  }

  ... the rest of this class

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

public LimitedSizeQueue<ElementType> implements Queue<ElementType>
{
    private int maxSize;
    private CircularFifoBuffer storageArea;

    public LimitedSizeQueue(final int maxSize)
    {
        if (maxSize > 0)
        {
            this.maxSize = maxSize;
            storateArea = new CircularFifoBuffer(maxSize);
        }
        else
        {
            throw new IllegalArgumentException("blah blah blah");
        }
    }

    ... implement the Queue interface using the CircularFifoBuffer class
}

2
+1 अगर आप समझाते हैं कि रचना एक बेहतर विकल्प क्यों है ("विरासत पर रचना पसंद करते हैं) के अलावा ... और एक बहुत अच्छा कारण है
kdgregory

1
रचना यहां मेरे काम के लिए एक खराब विकल्प है: इसका मतलब है कम से कम दो बार वस्तुओं की संख्या => कम से कम दो बार अधिक बार कचरा संग्रह। मैं इन सीमित आकार की कतारों की बड़ी मात्रा (दसियों लाख) का उपयोग करता हूं, जैसे: मैप <लॉन्ग, लिमिटेडसाइक्यूक्यू <स्ट्रींग >>।
ग्रेकैट

@ ग्रेकैट - मुझे लगता है कि आपने यह नहीं देखा कि LinkedListइसे कैसे लागू किया जाता है। सूची के चारों ओर आवरण के रूप में बनाई गई अतिरिक्त वस्तु बहुत मामूली होगी, यहां तक ​​कि उदाहरणों के "दसियों लाख" भी।
kdgregory

मैं "इंटरफ़ेस के आकार को कम करता है" के लिए जा रहा था, लेकिन "कार्यान्वयन को ढाल देता है" बहुत समान बात है। या तो ओपी के दृष्टिकोण के बारे में मार्क पीटर की शिकायतों का जवाब देता है ।
kdgregory

4

केवल एक चीज जो मुझे पता है कि सीमित स्थान है वह है ब्लॉकिंग क्यू इंटरफ़ेस (जो कि ArrayBlockingQueue वर्ग द्वारा कार्यान्वित किया जाता है) - लेकिन वे भरे जाने पर पहले तत्व को नहीं हटाते हैं, लेकिन इसके बजाय पुट ऑपरेशन को तब तक अवरुद्ध करते हैं जब तक कि स्थान खाली न हो (अन्य थ्रेड द्वारा हटा दिया गया) )।

मेरे ज्ञान के लिए आपका तुच्छ कार्यान्वयन इस तरह के व्यवहार को प्राप्त करने का सबसे आसान तरीका है।


मैं पहले से ही जावा stdlib कक्षाओं के माध्यम से ब्राउज़ कर चुका हूं, और, दुख की बात BlockingQueueहै कि इसका जवाब नहीं है। मैंने अन्य आम पुस्तकालयों के बारे में सोचा है, जैसे अपाचे कॉमन्स, एक्लिप्स लाइब्रेरी, स्प्रिंग, गूगल के अतिरिक्त, आदि?
ग्रेचैट

3

आप एक का उपयोग कर सकते MinMaxPriorityQueue से गूगल अमरूद जावाडोक से,:

न्यूनतम-अधिकतम प्राथमिकता वाली कतार को अधिकतम आकार के साथ कॉन्फ़िगर किया जा सकता है। यदि ऐसा है, तो हर बार कतार का आकार उस मान से अधिक हो जाता है, कतार अपने तुलनित्र के अनुसार अपने सबसे बड़े तत्व को हटा देती है (जो कि अभी जोड़ा गया तत्व हो सकता है)। यह पारंपरिक बंधी हुई कतारों से अलग है, जो पूर्ण होने पर नए तत्वों को अवरुद्ध या अस्वीकार करते हैं।


3
क्या आप समझते हैं कि प्राथमिकता कतार क्या है, और यह ओपी के उदाहरण से कैसे भिन्न है?
kdgregory

2
@ मर्क पीटर्स - मुझे नहीं पता कि क्या कहना है। निश्चित रूप से, आप एक प्राथमिकता कतार को व्यवहार में ला सकते हैं जैसे कि एक पण्य कतार। आप भी एक की Mapतरह व्यवहार कर सकते हैं List। लेकिन दोनों विचारों में एल्गोरिदम और सॉफ़्टवेयर डिज़ाइन की पूरी समझ नहीं है।
kdgregory

2
@ मार्क पीटर्स - कुछ करने के लिए एक अच्छे तरीके के बारे में एसओ पर हर सवाल नहीं है?
jtahlborn

3
@jtahlborn: स्पष्ट रूप से नहीं (कोड गोल्फ), लेकिन भले ही वे थे, अच्छा एक काले और सफेद मानदंड नहीं है। एक निश्चित परियोजना के लिए, अच्छे का अर्थ "सबसे अधिक कुशल" हो सकता है, दूसरे के लिए इसका मतलब "बनाए रखने में सबसे आसान" हो सकता है और दूसरे के लिए, इसका मतलब हो सकता है "मौजूदा पुस्तकालयों के साथ कम से कम कोड"। सब अप्रासंगिक है के बाद से मैं कभी नहीं कहा यह था एक अच्छा जवाब। मैंने सिर्फ इतना कहा कि यह बहुत अधिक प्रयास के बिना एक समाधान हो सकता है। MinMaxPriorityQueueओपी जो चाहता है, उसे संशोधित करने की तुलना में एक अधिक मोड़ है LinkedList(ओपी कोड भी करीब नहीं आता है)।
मार्क पीटर्स

3
हो सकता है कि आप लोग मेरी पसंद के शब्दों का परीक्षण कर रहे हों "व्यवहार में जो लगभग निश्चित रूप से पर्याप्त होंगे"। मेरा मतलब यह नहीं था कि यह समाधान लगभग निश्चित रूप से ओपी की समस्या या सामान्य रूप से पर्याप्त होगा। मैं longअपने स्वयं के सुझाव के भीतर एक कर्सर प्रकार के रूप में उतरने की पसंद का उल्लेख कर रहा था , यह कहते हुए कि यह व्यवहार में पर्याप्त रूप से व्यापक होगा भले ही सैद्धांतिक रूप से आप इस पंक्ति में 2 ^ 64 से अधिक ऑब्जेक्ट जोड़ सकते थे जिस बिंदु पर समाधान टूट जाएगा। ।
मार्क पीटर्स

3

एक LRUMap एक और संभावना है, जो अपाचे कॉमन्स से भी है।

http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/LRUMap.html


मैं वास्तव में समझ नहीं पा रहा हूं कि एक पंक्ति के रूप में कार्य करने के लिए LRUMap को कैसे अनुकूलित किया जाए और मुझे लगता है कि यदि संभव हो तो भी इसका उपयोग करना कठिन होगा।
ग्रेकट

-2
    public class ArrayLimitedQueue<E> extends ArrayDeque<E> {

    private int limit;

    public ArrayLimitedQueue(int limit) {
        super(limit + 1);
        this.limit = limit;
    }

    @Override
    public boolean add(E o) {
        boolean added = super.add(o);
        while (added && size() > limit) {
            super.remove();
        }
        return added;
    }

    @Override
    public void addLast(E e) {
        super.addLast(e);
        while (size() > limit) {
            super.removeLast();
        }
    }

    @Override
    public boolean offerLast(E e) {
        boolean added = super.offerLast(e);
        while (added && size() > limit) {
            super.pollLast();
        }
        return added;
    }
}

3
सवाल लोकप्रिय संग्रह कक्षा पुस्तकालयों में कक्षाओं के बारे में था, किसी के स्वयं के रोलिंग नहीं - न्यूनतम होमब्रेव "समाधान" पहले से ही प्रश्न में प्रदान किया गया था।
ग्रेचैट

2
इससे कोई फर्क नहीं पड़ता कि Google इस पृष्ठ को किसी अन्य प्रश्न =) पर भी
पाता है

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