2012-05-30 18 views
5

मैं रूबी स्क्रिप्ट में एक बड़ी सीएसवी फ़ाइल पार्स कर रहा हूं और कुछ खोज कुंजी से शीर्षक के लिए निकटतम मैच ढूंढने की आवश्यकता है। खोज कुंजी हो सकता है एक या अधिक मान और मान बिल्कुल नीचे के अनुसार मेल नहीं हो सकता है (करीब होना चाहिए)कीवर्ड के लिए रूबी खोज सरणी

search_keys = ["big", "bear"] 

डेटा है कि मैं के माध्यम से खोज करने की आवश्यकता युक्त एक बड़ा सरणी, केवल title स्तंभ पर खोज करना चाहते हैं :

array = [ 
      ["id", "title",   "code", "description"], 
      ["1", "once upon a time", "3241", "a classic story"], 
      ["2", "a big bad wolf", "4235", "a little scary"], 
      ["3", "three big bears", "2626", "a heart warmer"] 
     ] 

इस मामले मैं यह पंक्ति ["3", "three big bears", "2626", "a heart warmer"] वापस जाने के लिए के रूप में यह मेरी खोज कुंजी के लिए निकटतम मैच है चाहेगा में।

मैं चाहता हूं कि यह खोज कुंजी से निकटतम मैच वापस कर दे।

क्या कोई सहायक/पुस्तकालय/रत्न मैं उपयोग कर सकता हूं? किसी ने पहले यह किया ??

+0

एक मैच निर्धारित करने के लिए आपका मीट्रिक क्या है? – alex

+0

मैं कीवर्ड स्ट्रिंग 'शामिल करना' था, कीवर्ड, सभी कीवर्ड के लिए रिकर्सिवली और फिर उच्चतम हिट पंक्ति या – Norto23

उत्तर

1

मुझे लगता है कि आप इसे अपने आप कर सकते हैं और किसी भी रत्न का उपयोग करने की आवश्यकता नहीं है! यह आपकी आवश्यकता के करीब हो सकता है; चाबियों के लिए सरणी में खोज करना और प्रत्येक पाए गए तत्व के लिए रैंक सेट करना।

result = [] 
array.each do |ar| 
    rank = 0 
    search_keys.each do |key| 
     if ar[1].include?(key) 
      rank += 1 
     end 
    end 

    if rank > 0 
     result << [rank, ar] 
    end 
end 

यह कोड उपर्युक्त से बेहतर लिखा जा सकता है, लेकिन मैं आपको विवरण दिखाना चाहता था।

+0

जैसे कुछ प्राप्त करना यह नीचे आइसोटोप द्वारा प्रदान किए गए उत्तर के समान है, लेकिन रैंकिंग सिस्टम के साथ, मुझे पसंद है यह एक और लगता है कि मैं इसका इस्तेमाल कर सकता हूं। धन्यवाद। – Norto23

+1

मैंने रैंक द्वारा क्रमबद्ध करने के लिए आपके अंत में निम्नलिखित कोड जोड़ा। 'result.sort! {| ए, बी | बी [1] <=> एक [1]} ' – Norto23

2

मुझे चिंता है, इस कार्य को डीबी स्तर या इसी तरह के किसी भी खोज इंजन में संभाला जाना चाहिए, ऐप में डेटा लाने का कोई बिंदु नहीं है और कॉलम/पंक्तियों आदि में खोज करना महंगा होना चाहिए। लेकिन अब के लिए यहां सादा सरल दृष्टिकोण है :)

array = [ 
      ["id", "title",   "code", "description"], 
      ["1", "once upon a time", "3241", "a classic story"], 
      ["2", "a big bad wolf", "4235", "a little scary"], 
      ["3", "three big bears", "2626", "a heart warmer"] 
     ] 


h = {} 

search_keys = ["big", "bear"] 

array[1..-1].each do |rec| 
    rec_id = rec[0].to_i 

    search_keys.each do |key| 
    if rec[1].include? key 
     h[rec_id] = h[rec_id] ? (h[rec_id]+1) : 1 
    end 
    end 
end 

closest = h.keys.first 

h.each do |rec, count| 
    closest = rec if h[closest] < h[rec] 
end 

array[closest] # => desired output :) 
1

यह काम करता है। मिलान किए गए * पंक्तियों की एक सरणी result के रूप में मिल जाएगी और वापस लाएगी।

* मिलान पंक्तियां = एक पंक्ति जहां आईडी, शीर्षक, कोड या विवरण प्रदान की गई सीच_की में से कोई भी मेल खाता है। ऐसे में 'भालू' के रूप में सहित आंशिक खोजें 'भालू'

result = [] 
array.each do |a| 
    a.each do |i| 
     search_keys.each do |k| 
      result << a if i.include?(k) 
     end 
    end 
end 
result.uniq! 
+0

मुझे यह काम करने के लिए मिला, यह बहुत संक्षिप्त है। अगर मैं परिणाम प्राप्त कर सकता हूं .uni! उन्हें सॉर्ट करने के लिए ताकि उच्चतम डुप्लिकेट पहले हों, तो यह सही होगा। – Norto23

1

आप शायद एक और अधिक संक्षिप्त तरीके से लिख सकता है ...

array = [ 
      ["id", "title",   "code", "description"], 
      ["1", "once upon a time", "3241", "a classic story"], 
      ["2", "a big bad wolf", "4235", "a little scary"], 
      ["3", "three big bears", "2626", "a heart warmer"] 
     ] 
search_keys = ["big", "bear"] 


def sift(records, target_field, search_keys) 
    # find target_field index 
    target_field_index = nil 
    records.first.each_with_index do |e, i| 
     if e == target_field 
      target_field_index = i 
      break 
     end 
    end 
    if target_field_index.nil? 
     raise "Target field was not found" 
    end 

    # sums up which records have a match and how many keys they match 
    # key => val = record => number of keys matched 
    counter = Hash.new(0) # each new hash key is init'd with value of 0 

    records.each do |record| # look at all our given records 
     search_keys.each do |key| # check each search key on the field 
      if record[target_field_index].include?(key) 
       counter[record] += 1 # found a key, init to 0 if required and increment count 
      end 
     end 
    end 

    # find the result with the most search key matches 
    top_result = counter.to_a.reduce do |top, record| 
     if record[1] > top[1] # [0] = record, [1] = key hit count 
      top = record # set to new top 
     end 
     top # continue with reduce 
    end.first # only care about the record (not the key hit count) 
end 


puts "Top result: #{sift array, 'title', search_keys}" 
# => Top result: ["3", "three big bears", "2626", "a heart warmer"] 
1
यहाँ

मेरी एक-पंक्ति गोली मार दी

p array.find_all {|a|a.join.scan(/#{search_keys.join("|")}/).length==search_keys.length} 
=>[["3", "three big bears", "2626", "a heart warmer"]] 
है

मैचों की संख्या के क्रम में सभी पंक्तियां प्राप्त करने

p array.drop(1).sort_by {|a|a.join.scan(/#{search_keys.join("|")}/).length}.reverse 

कोई भी जानता है कि आखिरी समाधान को कैसे जोड़ना है ताकि पंक्तियों में से कोई भी पंक्ति न हो और इसे संक्षिप्त बनाए रखा जाए?

+0

यह समाधान बहुत अच्छा लगता है।मुझे पहली पंक्ति काम नहीं मिल सका, लेकिन मुझे बिना किसी हिट के सभी परिणामों को छोड़ने के लिए दूसरी पंक्ति मिल सकती है, यह बहुत उपयोगी होगा। – Norto23

+0

सुनने के लिए अच्छा है लेकिन यह मुझे आश्चर्यचकित करता है कि उनमें से एक काम नहीं करेगा, क्या आप रूबी 1 9 3 का उपयोग करते हैं, फिर उन्हें दोनों को काम करना चाहिए, पहले आपके मल्टीडिमेन्शन सरणी का एक फ़िल्टर संस्करण प्रदान करता है, दूसरा एक सॉर्टेड संस्करण हेडरो – peter

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