मुझे स्केल में वेक्टर कब चुनना चाहिए?


200

ऐसा लगता है कि Vectorस्काला संग्रह पार्टी के लिए देर हो चुकी थी, और सभी प्रभावशाली ब्लॉग पोस्ट पहले ही निकल गए थे।

जावा ArrayListमें डिफ़ॉल्ट संग्रह है - मैं उपयोग कर सकता हूं LinkedListलेकिन केवल जब मैंने एक एल्गोरिथ्म के माध्यम से सोचा है और अनुकूलन करने के लिए पर्याप्त देखभाल की है। स्काला में मुझे Vectorअपने डिफ़ॉल्ट के रूप में उपयोग करना चाहिए Seq, या Listवास्तव में अधिक उपयुक्त होने पर काम करने की कोशिश करनी चाहिए?


1
मुझे लगता है कि मेरा यहाँ जो मतलब है वह यह है कि जावा में मैं List<String> l = new ArrayList<String>()स्कैला ब्लॉग बनाऊंगा क्या आप मानते होंगे कि निरंतर संग्रह अच्छाई पाने के लिए हर कोई सूची का उपयोग करता है - लेकिन क्या सदिश सामान्य उद्देश्य पर्याप्त है कि हम इसका उपयोग सूची में जगह पर करें?
डंकन मैकग्रेगर

9
@डेबिल्स्की: मैं सोच रहा हूं कि आपका क्या मतलब है। Listजब मैं Seq()REPL में टाइप करता हूं तो मुझे मिलता है ।
17.1 पर लापताफोटोर

1
हम्म, ठीक है, यह डॉक्स में ऐसा कहता है। शायद यह केवल सच हो IndexedSeq
देबिल्स्की

1
डिफ़ॉल्ट कंक्रीट प्रकार के बारे में टिप्पणी Seqतीन साल से अधिक पुरानी है। स्केल 2.11.4 (और पहले) के रूप में, डिफ़ॉल्ट ठोस प्रकार Seqहै List
मार्क कैनलस

3
यादृच्छिक अभिगम के लिए, वेक्टर बेहतर है। हेड, टेल एक्सेस के लिए, सूची बेहतर है। बल्क ऑपरेशन के लिए, जैसे कि मैप, फिल्टर, वेक्टर को पसंद किया जाता है क्योंकि वेक्टर को 32 तत्वों के साथ एक चंक के रूप में व्यवस्थित किया जाता है जबकि सूची एक दूसरे के लिए पॉइंटर्स वाले तत्वों को व्यवस्थित करती है कोई गारंटी नहीं है कि ये तत्व एक दूसरे के करीब हैं।
जॉन्साम

जवाबों:


280

एक सामान्य नियम के रूप में, उपयोग करने के लिए डिफ़ॉल्ट Vector। यह लगभग हर चीज के Listलिए तेज है और बड़े-से-तुच्छ आकार के दृश्यों के लिए अधिक मेमोरी-कुशल है। अन्य संग्रह की तुलना में वेक्टर के सापेक्ष प्रदर्शन के इस प्रलेखन को देखें । साथ जाने के लिए कुछ डाउनसाइड हैं । विशेष रूप से:Vector

  • सिर पर अपडेट की तुलना में धीमी गति से List(हालांकि जितना आप सोच सकते हैं उतना नहीं है)

स्केला 2.10 से पहले एक और नकारात्मक पहलू यह था कि पैटर्न मिलान समर्थन के लिए बेहतर था List, लेकिन सामान्यीकृत +:और :+चिमटा के साथ 2.10 में यह ठीक किया गया था ।

अनुक्रम की तरह क्या आप करते हैं: वहाँ भी एक और अधिक सार, इस सवाल के करीब पहुंच के बीजीय तरीका है धारणात्मक है? इसके अलावा, क्या आप कर रहे हैं धारणात्मक इसके साथ कर रही है? यदि मुझे कोई फ़ंक्शन दिखाई देता है जो एक रिटर्न देता है Option[A], तो मुझे पता है कि फ़ंक्शन के डोमेन में कुछ छेद हैं (और इस प्रकार आंशिक है)। हम इसी तर्क को संग्रह में लागू कर सकते हैं।

यदि मेरे पास प्रकार का अनुक्रम है List[A], तो मैं प्रभावी रूप से दो चीजों पर जोर दे रहा हूं। सबसे पहले, मेरा एल्गोरिथ्म (और डेटा) पूरी तरह से स्टैक-संरचित है। दूसरा, मैं यह दावा कर रहा हूं कि इस संग्रह के साथ मैं केवल वही चीजें करने जा रहा हूं जो पूर्ण हैं, ओ (एन) ट्रैवर्सल्स। ये दोनों वास्तव में हाथ से जाते हैं। इसके विपरीत, अगर मेरे पास कुछ प्रकार है Vector[A], तो केवल एक चीज जो मैं बता रहा हूं वह यह है कि मेरे डेटा में एक अच्छी तरह से परिभाषित क्रम और एक महीन लंबाई है। इस प्रकार, दावे के साथ कमजोर हैं Vector, और यह इसके अधिक लचीलेपन की ओर जाता है।


2
2.10 कुछ समय के लिए बाहर हो गया है, क्या सूची पैटर्न अभी भी वेक्टर से बेहतर है?
टिम गौटियर

3
सूची पैटर्न का मिलान अब बेहतर नहीं है। वास्तव में, यह काफी विपरीत है। उदाहरण के लिए, सिर और पूंछ प्राप्त करने के लिए कोई कर सकता है case head +: tailया case tail :+ head। खाली के खिलाफ मैच करने के लिए, आप कर सकते हैं case Seq()और आगे। एपीआई में आपकी जरूरत की हर चीज मौजूद है, जो List
बजे

Listएक एकल-लिंक्ड सूची के साथ कार्यान्वित किया जाता है। Vectorकुछ जावा की तरह लागू किया गया है ArrayList
योशिय्याह योडर

6
@ जोसाइयोडर यह एरियर लाईट जैसा कुछ भी नहीं है। ArrayList एक सरणी लपेटता है जिसे यह गतिशील रूप से आकार देता है। वेक्टर एक ट्राइ है , जहाँ कुंजियाँ मानों की अनुक्रमणिका होती हैं।
जॉन कोलंडोनी

1
मैं क्षमाप्रार्थी हूं। मैं एक वेब-स्रोत पर जा रहा था जो विवरण के बारे में अस्पष्ट था। क्या मुझे अपना पूर्व कथन सही करना चाहिए? या वह बुरा रूप है?
योशिय्याह योडर

93

ठीक है, एक Listअविश्वसनीय रूप से तेजी से हो सकता है अगर एल्गोरिथ्म को पूरी तरह से लागू किया जा सकता है ::, headऔर tail। मेरे पास बहुत हाल ही में एक वस्तु का पाठ था, जब मैंने जावा को splitएक के Listबजाय उत्पन्न करके हराया था Array, और इसे किसी और चीज के साथ नहीं हरा सका।

हालांकि, Listएक मौलिक समस्या है: यह समानांतर एल्गोरिदम के साथ काम नहीं करता है। मैं Listएक कुशल खंड में कई खंडों में विभाजित नहीं कर सकता , या इसे वापस नहीं ले सकता।

अन्य प्रकार के संग्रह हैं जो समानता को बेहतर तरीके से संभाल सकते हैं - और Vectorउनमें से एक है। Vectorइसमें बहुत बड़ा इलाका है - जो Listनहीं है - जो कुछ एल्गोरिदम के लिए एक वास्तविक प्लस हो सकता है।

इसलिए, सभी बातों पर विचार Vectorकिया जाना सबसे अच्छा विकल्प है, जब तक कि आपके पास विशिष्ट विचार हों, जो अन्य संग्रह में से एक को बेहतर बनाते हैं - उदाहरण के लिए, आप चुन सकते हैं Streamकि क्या आप आलसी मूल्यांकन और कैशिंग चाहते हैं ( Iteratorतेज है, लेकिन कैश नहीं है), या Listयदि एल्गोरिथ्म स्वाभाविक रूप से मेरे द्वारा उल्लिखित संचालन के साथ लागू किया गया है।

वैसे, इसका इस्तेमाल बेहतर है Seqया IndexedSeqजब तक आप एपीआई के किसी विशिष्ट अंश (जैसे चाहते Listहै ::), या यहाँ तक GenSeqया GenIndexedSeqयदि आपके एल्गोरिथ्म समानांतर में चलाया जा सकता है।


3
जवाब के लिए धन्यवाद। "आपके पास महान स्थानीयता" से क्या मतलब है?
Ngoc Dao

10
@ngocdaothanh इसका मतलब है कि डेटा को मेमोरी में एक साथ निकटता से वर्गीकृत किया गया है, जिससे डेटा को कैश में होने की संभावना में सुधार होगा।
डैनियल सी। सोबराल

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

1
@ user247077 शायद आपको पता नहीं है कि Vectorस्काला में एक अपरिवर्तनीय डेटा संरचना है?
डैनियल सी। सोबरल

1
@ user247077 यह उससे अधिक जटिल है, जिसमें एपेंड को सस्ता बनाने के लिए कुछ आंतरिक रूप से परिवर्तनशील सामान शामिल है, लेकिन जब आप इसे एक स्टैक के रूप में उपयोग करते हैं, जो अपरिवर्तनीय सूची इष्टतम परिदृश्य है, तो आप अभी भी एक लिंक्ड सूची की समान मेमोरी विशेषताओं वाले हैं, लेकिन एक बहुत बड़ी मेमोरी आवंटन प्रोफ़ाइल के साथ।
डैनियल सी। सोबरल

29

यहाँ कुछ कथन भ्रामक या गलत भी हैं, विशेष रूप से यह विचार कि अपरिवर्तनीय है। स्काला में वैक्टर कुछ भी है जैसे एक अरैस्टिस्ट। सूची और वेक्टर दोनों अपरिवर्तनीय हैं, लगातार (यानी "एक संशोधित प्रतिलिपि प्राप्त करने के लिए सस्ते") डेटा संरचनाएं। कोई उचित डिफ़ॉल्ट विकल्प नहीं है, क्योंकि उनका परिवर्तन योग्य डेटा संरचनाओं के लिए हो सकता है, लेकिन यह इस बात पर निर्भर करता है कि आपका एल्गोरिथ्म क्या कर रहा है। सूची एक एकल रूप से जुड़ी हुई सूची है, जबकि वेक्टर एक बेस -32 पूर्णांक त्रिक है, अर्थात यह डिग्री 32 के नोड्स के साथ एक प्रकार का खोज वृक्ष है। इस संरचना का उपयोग करते हुए, वेक्टर सबसे आम संचालन को तेजी से प्रदान कर सकता है, अर्थात O (log_32 में) एन))। यह प्रीपेंड, एपेंड, अपडेट, रैंडम एक्सेस, हेड / टेल में अपघटन का काम करता है। अनुक्रमिक क्रम में परिवर्तन रैखिक है। दूसरी ओर सूची बस रैखिक पुनरावृत्ति और निरंतर समय प्रदान करता है, सिर / पूंछ में अपघटन।

ऐसा लग सकता है कि वेक्टर लगभग सभी मामलों में सूची के लिए एक अच्छा प्रतिस्थापन था, लेकिन एक कार्यात्मक कार्यक्रम में अनुक्रमों पर प्रायश्चित, विघटन और पुनरावृत्ति अक्सर महत्वपूर्ण संचालन होते हैं, और इन कार्यों के स्थिरांक वेक्टर के लिए अधिक (बहुत) होते हैं इसकी अधिक जटिल संरचना के लिए। मैंने कुछ माप किए, इसलिए पुनरावृत्ति सूची के लिए लगभग दोगुनी है, सूचियों पर प्रिपेंड लगभग 100 गुना तेज है, सिर / पूंछ में अपघटन सूचियों पर लगभग 10 गुना तेज है और ट्रैवर्सेबल से पीढ़ी वैक्टर के लिए लगभग 2 गुना तेज है। (यह संभवतः है, क्योंकि वेक्टर एक बार में 32 तत्वों के सरणियों को आवंटित कर सकता है जब आप इसे एक या एक करके तत्वों को जोड़ने या जोड़ने के बजाय एक बिल्डर का उपयोग करके बनाते हैं)।

तो हमें कौन सी डेटा संरचना का उपयोग करना चाहिए? मूल रूप से, चार सामान्य मामले हैं:

  • हमें केवल मानचित्र, फ़िल्टर, तह आदि जैसे कार्यों द्वारा अनुक्रम को बदलने की आवश्यकता है: मूल रूप से यह कोई फर्क नहीं पड़ता है, हमें अपने एल्गोरिथ्म को उदारतापूर्वक प्रोग्राम करना चाहिए और समानांतर अनुक्रमों को स्वीकार करने से भी लाभ हो सकता है। अनुक्रमिक संचालन के लिए सूची शायद थोड़ी तेज है। लेकिन अगर आपको अनुकूलन करना है तो आपको इसे बेंचमार्क करना चाहिए।
  • हमें बहुत अधिक यादृच्छिक पहुंच और विभिन्न अपडेट की आवश्यकता है, इसलिए हमें वेक्टर का उपयोग करना चाहिए, सूची निषेधात्मक रूप से धीमी होगी।
  • हम एक शास्त्रीय कार्यात्मक तरीके से सूचियों पर काम करते हैं, उन्हें पुनर्संरचना अपघटन द्वारा तैयार और पुनरावृत्त करके निर्माण करते हैं: सूची का उपयोग करें, वेक्टर एक कारक 10-100 या अधिक द्वारा धीमा हो जाएगा।
  • हमारे पास एक प्रदर्शन महत्वपूर्ण एल्गोरिथ्म है जो मूल रूप से अत्यावश्यक है और एक सूची पर बहुत अधिक यादृच्छिक अभिगम करता है, जैसे कि जगह में त्वरित रूप से कुछ: एक अनिवार्य डेटा संरचना का उपयोग करें, जैसे कि ArrayBuffer, स्थानीय रूप से और इसके लिए अपना डेटा कॉपी करें।

24

अपरिवर्तनीय संग्रह के लिए, यदि आप एक अनुक्रम चाहते हैं, तो आपका मुख्य निर्णय यह है कि क्या एक IndexedSeqया एक का उपयोग करें LinearSeq, जो प्रदर्शन के लिए अलग-अलग गारंटी देता है। एक IndexedSeq तत्वों की तेजी से यादृच्छिक-पहुँच और एक तेज़ लंबाई ऑपरेशन प्रदान करता है। एक LinearSeq केवल पहले तत्व के माध्यम से तेजी से पहुंच प्रदान करता है head, लेकिन इसका एक तेज tailसंचालन भी है । (Seq प्रलेखन से लिया गया।)

एक के लिए IndexedSeqआप सामान्य रूप से एक का चयन करेंगे VectorRanges और WrappedStrings भी IndexedSeqs हैं।

एक के लिए LinearSeqआप सामान्य रूप से एक का चयन करेंगे Listया उसके आलसी बराबर Stream। अन्य उदाहरण Queueएस एंड Stackएस हैं।

तो जावा शब्दों में, ArrayListस्काला के समान उपयोग किया जाता है Vector, और LinkedListस्काला के समान List। लेकिन Scala में मैं वेक्टर की तुलना में अधिक बार सूची का उपयोग करना चाहूंगा, क्योंकि Scala के पास कार्यों के लिए बहुत बेहतर समर्थन है, जिसमें अनुक्रम का अनुक्रमण शामिल है, जैसे मैपिंग, फोल्डिंग, पुनरावृत्ति आदि। आप इन कार्यों का उपयोग सूची के रूप में हेरफेर करने के लिए करेंगे। पूरे, बल्कि व्यक्तिगत तत्वों को बेतरतीब ढंग से एक्सेस करने के बजाय।


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

@ डंकन जहां आपने सुना है कि वेक्टर का चलना तेज है? एक शुरुआत के लिए, आपको वर्तमान सूचकांक को ट्रैक करने और अपडेट करने की आवश्यकता है, जिसे आपको लिंक की गई सूची के साथ करने की आवश्यकता नहीं है। मैं सूची कार्यों को "विशेष मामलों" नहीं कहूंगा - वे कार्यात्मक प्रोग्रामिंग की रोटी और मक्खन हैं। उनका उपयोग न करना, जावा के लिए- या जबकि-लूप के बिना प्रोग्राम करने की कोशिश करने जैसा होगा।
लुइगी प्लिंज

2
मैं बहुत यकीन है कि Vector's यात्रा है तेजी से, लेकिन यह बेंचमार्क के लिए किसी की जरूरत है सुनिश्चित करने के लिए।
डैनियल स्प्युकक

मुझे लगता है कि () Vectorभौतिक रूप से 32 के समूहों में रैम पर एक साथ मौजूद हैं, जो सीपीयू कैश में पूरी तरह से फिट हैं ... इसलिए कम कैश मिस है
रिचीज़

2

जिन स्थितियों में बहुत यादृच्छिक अभिगम और यादृच्छिक उत्परिवर्तन शामिल होता है, Vector(या - जैसा कि डॉक्स कहते हैं - ए Seq) एक अच्छा समझौता लगता है। यह भी प्रदर्शन विशेषताओं का सुझाव है।

इसके अलावा, Vectorवर्ग बहुत अधिक डेटा डुप्लीकेशन के बिना वितरित वातावरण में अच्छी तरह से खेलता है क्योंकि संपूर्ण ऑब्जेक्ट के लिए कॉपी-ऑन-राइट करने की आवश्यकता नहीं है। (देखें: http://akka.io/docs/akka/1.1.3/scala/stm.html#persistent-datastructures )


1
इतना कुछ सीखना ... क्या वेक्टर डिफ़ॉल्ट Seq का मतलब है? अगर मैं Seq (1, 2, 3) लिखता हूं तो मुझे सूची [इंट] मिलती है न कि वेक्टर [इंट]।
डंकन मैकग्रेगर

2
यदि आपके पास रैंडम एक्सेस है, तो ए का उपयोग करें IndexedSeq। जो है भी Vector, लेकिन वह दूसरी बात है।
डैनियल सी। सोबरल

@DuncanMcGregor: वेक्टर वह डिफ़ॉल्ट है IndexedSeqजो लागू करता है SeqSeq(1, 2, 3)एक LinearSeqका उपयोग कर कार्यान्वित किया जाता है List
पाथिकृत

0

यदि आप अपरिवर्तनीय रूप से प्रोग्रामिंग कर रहे हैं और यादृच्छिक अभिगम की आवश्यकता है, तो Seq जाने का मार्ग है (जब तक कि आप एक सेट नहीं चाहते हैं, जो आप वास्तव में करते हैं)। अन्यथा सूची अच्छी तरह से काम करती है, सिवाय इसके कि संचालन को समानांतर नहीं किया जा सकता है।

यदि आपको अपरिवर्तनीय डेटा संरचनाओं की आवश्यकता नहीं है, तो ArrayBuffer के साथ रहें क्योंकि यह ArrayList के समान Scala है।


मैं अपरिवर्तनीय, लगातार संग्रह के दायरे से चिपका हुआ हूं। मेरी बात यह है कि, भले ही मुझे यादृच्छिक अभिगम की आवश्यकता न हो, क्या वेक्टर को प्रभावी रूप से सूची में बदल दिया गया है?
डंकन मैकग्रेगर

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

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