2015-03-31 8 views
7

मैं विशाल संग्रह से शीर्ष एन तत्वों को खोजने के लिए जावा में एक मेमोरी-कुशल तरीका ढूंढ रहा हूं। उदाहरण के लिए, मेरे पास एक शब्द, एक दूरी() विधि है, और "सभी" शब्दों का संग्रह है। मैंने एक कक्षा जोड़ी लागू की है जो तुलना करता है() ताकि जोड़े को उनके मूल्यों से क्रमबद्ध किया जा सके।जावा स्ट्रीम का उपयोग कर MinMaxPriorityQueue

धाराओं का उपयोग करना, मेरी भोली समाधान इस तरह दिखता है:

double distance(String word1, String word2){ 
    ... 
} 

Collection<String> words = ...; 
String word = "..."; 

words.stream() 
    .map(w -> new Pair<String, Double>(w, distance(word, w))) 
    .sorted() 
    .limit(n); 

मेरी समझ के लिए, इस पर कार्रवाई और intermediately शब्दों में प्रत्येक तत्व की दुकान इतना है कि यह सीमा लागू करने से पहले हल हो सकते हैं()। हालांकि, यह एक संग्रह रखने के लिए अधिक स्मृति-कुशल है जो एन तत्वों को संग्रहीत करता है और जब भी कोई नया तत्व जोड़ा जाता है, तो यह सबसे छोटा तत्व (तुलनीय वस्तु के प्राकृतिक क्रम के अनुसार) को हटा देता है और इस प्रकार एन (या एन + 1) से बड़ा नहीं होता है।)।

यह ठीक है कि अमरूद MinMaxPriorityQueue करता है। इस प्रकार, ऊपर समस्या के लिए अपने मौजूदा सबसे अच्छा समाधान यह है:

Queue<Pair<String, Double>> neighbours = MinMaxPriorityQueue.maximumSize(n).create(); 
words.stream() 
    .forEach(w -> neighbours.add(new Pair<String, Double>(w, distance(word, w))); 

शीर्ष n तत्वों का छंटाई एक धारा या सूची में कतार परिवर्तित करने के बाद किया जाना रहता है, लेकिन यह कोई मुद्दा n है के बाद से नहीं है अपेक्षाकृत छोटा।

मेरा प्रश्न है: क्या धाराओं का उपयोग करके ऐसा करने का कोई तरीका है?

+3

यह 'MinMaxPriorityQueue' के सभी बिंदुओं पर नहीं है: 'MinMaxPriorityQueue' का एकमात्र बिंदु तब होता है जब आपको वास्तव में सबसे बड़ी और निम्नतम तत्वों तक पहुंचने के लिए डबल-एंड प्राथमिकता कतार की आवश्यकता होती है, जो ऐसा प्रतीत नहीं होता है यहां मामला 'अधिकतम आकार' पहलू डेटा संरचना का बिंदु नहीं है, और यह गंभीर रूप से अक्षम होगा। अमरूद के 'ऑर्डरिंग.greatestOf' फ़ंक्शन को इस सटीक उपयोग के मामले के लिए कड़ाई से अनुकूलित किया गया है, और ओ (एन लॉग एन) के बजाय ओ (एन) समय लेता है। –

+1

(गुवा के भविष्य संस्करणों में 'ऑर्डरिंग.greatestOf' का संस्करण होगा जो विशेष रूप से जावा 8 कलेक्टर एपीआई से मेल खाने के लिए डिज़ाइन किया गया है।) –

+0

पॉइंटर के लिए धन्यवाद! मुझे ऑर्डरिंग.greatestOf() का उपयोग करने के लिए पहले एक संग्रह में सभी तत्वों को संग्रहीत किए बिना एक तरीका नहीं दिख रहा है, क्या कोई है? या जैसा कि आपने उल्लेख किया है, भविष्य के संस्करणों में यह केवल संभव होगा? – Carsten

उत्तर

2

एक विशाल ढांचा संरचना पूरी विशाल सूची को सॉर्ट करने से निश्चित रूप से अधिक कुशल होगी। सौभाग्य से, धाराओं पुस्तकालय पूरी तरह से आप विशेष संग्रह का उपयोग जब आवश्यक बताते हुए खुशी हो रहा है:

MinMaxPriorityQueue<Pair<String, Double>> topN = words.stream() 
    .map(w -> new Pair<String, Double>(w, distance(word, w))) 
    .collect(toCollection(
      () -> MinMaxPriorityQueue.maximumSize(n).create() 
    )); 

यह .forEach समाधान से बेहतर है यह parallelize आसान है और अधिक मुहावरेदार java8 है क्योंकि।

नोट करें कि () -> MinMaxPriorityQueue.maximumSize(n).create()MinMaxPriorityQueue.maximumSize(n)::create के साथ प्रतिस्थापित किया जाना चाहिए, लेकिन किसी कारण से, यह कुछ शर्तों के तहत संकलित नहीं होगा (नीचे टिप्पणियां देखें)।

+0

आपको बहुत धन्यवाद @ मिशा, ऐसा लगता है कि मैं जिस समाधान की तलाश में था। हालांकि, कोड में आपके अंतिम संपादन के बाद से, यह अब संकलित नहीं होता है: 'प्रकार MinMaxPriorityQueue.Builder परिभाषित नहीं करता है() जो यहां लागू है। यह पिछले आकार में ठीक था हालांकि: 'toCollection (() -> MinMaxPriorityQueue.maximumSize (n) .create()) '। परिवर्तन के लिए आपका कारण क्या था? – Carsten

+1

@ करस्टन अजीब। मैंने बस कोशिश की और यह jdk 1.8 के साथ ठीक संकलित।0_25 – Misha

+1

@ कार्स्टन कम ब्रांड्स इसे थोड़ा स्पष्ट (मेरे स्वाद के लिए) बनाते हैं। जेडीके का कौन सा संस्करण आप इसे संकलित कर रहे हैं? – Misha

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