O (n) से अधिक सरणी तत्व का सूचकांक प्राप्त करें


104

यह देखते हुए कि मेरे पास एक विशाल सरणी है, और उससे एक मूल्य है। मैं सरणी में मान का सूचकांक प्राप्त करना चाहता हूं। क्या कोई और रास्ता है, बल्कि Array#indexइसे प्राप्त करने के लिए कॉल करें ? समस्या वास्तव में विशाल सरणी रखने और Array#indexभारी मात्रा में कॉल करने की आवश्यकता से आती है ।

कुछ प्रयासों के बाद मैंने पाया कि मूल्य के बजाय खेतों के साथ संरचनाओं को संचय करके तत्वों के अंदर कैशिंग इंडेक्स (value, index)प्रदर्शन में एक बड़ा कदम देता है (20x बार जीत)।

फिर भी मुझे आश्चर्य है कि अगर कैशिंग के बिना एन तत्व के सूचकांक को खोजने का एक और अधिक सुविधाजनक तरीका है (या एक अच्छी कैशिंग तकनीक है जो प्रदर्शन को बढ़ावा देगी)।

जवाबों:


118

सरणी को हैश में परिवर्तित करें। फिर चाबी की तलाश करें।

array = ['a', 'b', 'c']
hash = Hash[array.map.with_index.to_a]    # => {"a"=>0, "b"=>1, "c"=>2}
hash['b'] # => 1

2
सबसे तेज़ अगर सरणी बहुत लंबी है
केविन

17
आपके उपयोग के मामले के आधार पर यह समस्याग्रस्त हो सकता है यदि डुप्लिकेट मान हैं। ऊपर वर्णित विधि समतुल्य या #rindex (मान की अंतिम घटना) लौटाएगी #index समतुल्य परिणाम प्राप्त करने के लिए, जिसका अर्थ है कि मान बनाने के पहले इंडेक्स को वापस करने से पहले आपको सरणी बनाने के लिए कुछ और करना होगा। हैश तब प्रारंभिक सरणी की कुल लंबाई से लौटे हुए सूचकांक मान को घटाता है - 1. # (array.length - 1) - हैश ['बी']
ashoda

2
क्या हैश ओ (n) समय में रूपांतरण नहीं होता है? मुझे लगता है कि अगर यह एक से अधिक बार उपयोग होने जा रहा है, तो हैश रूपांतरण अधिक निष्पादक होगा। लेकिन एकल उपयोग के लिए, क्या यह अलग नहीं है तो सरणी के माध्यम से पुनरावृति?
अहानिबेकाड

हाँ, और शायद एकल उपयोग के लिए इससे भी बदतर अगर यह वास्तव में हैश की गणना के रूप में मायने रखता है तो तुलना के रूप में जल्दी से शॉर्ट-सर्किट नहीं होगा।
पीटर डेविस

199

सूचकांक या रिंडेक्स का उपयोग क्यों नहीं किया जाता है?

array = %w( a b c d e)
# get FIRST index of element searched
puts array.index('a')
# get LAST index of element searched
puts array.rindex('a')

सूचकांक: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-index

rindex: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-rindex


13
यह वही है जो ओपी ने कहा था कि वे अपने सरणी के बड़े आकार के कारण डीआईडीएन नहीं चाहते हैं। Array # index O (n) है और ऐसा करने से कई बार प्रदर्शन पर मार पड़ेगी। हैश लुकिंग O (1) है।
टिम

4
@ यह अच्छी तरह से, मैं अपने जवाब के समय याद नहीं कर सकता कि यह एक ही सवाल था, शायद ओपी ने बाद में इस सवाल को संशोधित किया, जो इस उत्तर को अमान्य कर देगा।
रोजर

3
क्या यह नहीं कहेंगे कि इसे एक विशिष्ट समय में संपादित किया गया था?
टिम

हे, हाँ, यह सच है। खैर मैं और एक अन्य 30 लोग उस पर पढ़ रहे थे। मुझे लगता है: /
रोजर

9

अन्य उत्तर एक सरणी में कई बार सूचीबद्ध प्रविष्टि की संभावना को ध्यान में नहीं रखते हैं। यह एक हैश लौटाएगा जहां प्रत्येक कुंजी सरणी में एक अद्वितीय वस्तु है और प्रत्येक मूल्य सूचकांकों की एक सरणी है जो उस वस्तु से मेल खाती है जहां वस्तु रहती है:

a = [1, 2, 3, 1, 2, 3, 4]
=> [1, 2, 3, 1, 2, 3, 4]

indices = a.each_with_index.inject(Hash.new { Array.new }) do |hash, (obj, i)| 
    hash[obj] += [i]
    hash
end
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5], 4 => [6] }

यह डुप्लिकेट प्रविष्टियों के लिए त्वरित खोज की अनुमति देता है:

indices.select { |k, v| v.size > 1 }
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5] }

6

क्या हैश का उपयोग न करने का एक अच्छा कारण है? लुकअप सरणी के लिए O(1)बनाम हैं O(n)


मुद्दा यह है - मैं #keysहैश पर कॉल कर रहा हूं , जो एक सरणी देता है जिसका मैं उपयोग कर रहा हूं। फिर भी, मैं अपनी वास्तुकला के बारे में सोच सकता हूँ ...
gmile

3

यदि यह एक सॉर्ट किया गया सरणी है, तो आप बाइनरी खोज एल्गोरिथ्म ( O(log n)) का उपयोग कर सकते हैं । उदाहरण के लिए, इस कार्यक्षमता के साथ ऐरे-वर्ग का विस्तार करना:

class Array
  def b_search(e, l = 0, u = length - 1)
    return if lower_index > upper_index

    midpoint_index = (lower_index + upper_index) / 2
    return midpoint_index if self[midpoint_index] == value

    if value < self[midpoint_index]
      b_search(value, lower_index, upper_index - 1)
    else
      b_search(value, lower_index + 1, upper_index)
    end
  end
end

3
यह वास्तव में पढ़ना मुश्किल नहीं है। पहला भाग, यदि ऊपरी बाउंड से कम बाउंड बड़ा है (पुनरावृत्ति दर्ज किया गया है)। दूसरा भाग यह जाँचता है कि क्या हमें उस बिंदु पर मूल्य के साथ midpoint m की तुलना करके बाईं ओर या दाईं ओर की आवश्यकता है। यदि हमारे पास वह उत्तर नहीं है, जो हम चाहते हैं, तो हम पुनः प्राप्त करते हैं।
ioquatix

मुझे लगता है कि यह संपादन करने के बजाय नीच लोगों के अहंकार को बेहतर करता है।
आंद्रे फिग्यूएरेडो

2

@ साया के उत्तर और वहां सूचीबद्ध टिप्पणी के संयोजन को लेते हुए आप सरणी वर्ग पर एक "त्वरित" सूचकांक और रिंडेक्स को लागू कर सकते हैं।

class Array
  def quick_index el
    hash = Hash[self.map.with_index.to_a]
    hash[el]
  end

  def quick_rindex el
    hash = Hash[self.reverse.map.with_index.to_a]
    array.length - 1 - hash[el]
  end
end

2

यदि आपके सरणी में एक प्राकृतिक क्रम बाइनरी खोज का उपयोग है।

बाइनरी खोज का उपयोग करें।

बाइनरी सर्च का O(log n)एक्सेस टाइम है।

यहाँ द्विआधारी खोज का उपयोग करने के तरीके दिए गए हैं,

  • आप सरणी का आदेश क्या है? उदाहरण के लिए, क्या यह नाम से क्रमबद्ध है?
  • bsearchतत्वों या सूचकांकों को खोजने के लिए उपयोग करें

कोड उदाहरण

# assume array is sorted by name!

array.bsearch { |each| "Jamie" <=> each.name } # returns element
(0..array.size).bsearch { |n| "Jamie" <=> array[n].name } # returns index

0

फिर भी मुझे आश्चर्य है कि अगर कैशिंग के बिना एन तत्व के सूचकांक को खोजने का एक और अधिक सुविधाजनक तरीका है (या एक अच्छी कैशिंग तकनीक है जो प्रदर्शन को बढ़ावा देगी)।

आप द्विआधारी खोज का उपयोग कर सकते हैं (यदि आपकी सरणी का आदेश दिया गया है और आपके द्वारा सरणी में संग्रहीत मान किसी तरह से तुलनीय हैं)। उस काम के लिए आपको द्विआधारी खोज को यह बताने में सक्षम होना चाहिए कि क्या उसे मौजूदा तत्व के लिए "बाईं ओर" या "दाईं ओर" दिखना चाहिए। लेकिन मेरा मानना ​​है कि indexसम्मिलन समय पर भंडारण के साथ कुछ भी गलत नहीं है और यदि आप उसी सरणी से तत्व प्राप्त कर रहे हैं तो इसका उपयोग करें।

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