2010-11-03 17 views
6

मैं रुबी 1.8.7 का उपयोग कर रहा हूं। मेरे पास हैश की निम्न सरणी है। मुझे पहले बूलियन मान द्वारा क्रमबद्ध करने की आवश्यकता है, लेकिन उन परिणामों को मूल क्रम में भी आदेश दिया जाना चाहिए। मुझे मूल रूप से सरणी के शीर्ष पर सभी सच्चे हैंश को स्थानांतरित करने की आवश्यकता है लेकिन मूल क्रम को बनाए रखना है।बूलियन द्वारा संख्या रूबी और संख्या

किसी भी मदद की सराहना की जाएगी!

array = [{:id => 1, :accepts => false}, 
     {:id => 2, :accepts => false}, 
     {:id => 3, :accepts => true}, 
     {:id => 4, :accepts => false}, 
     {:id => 5, :accepts => true}] 

sorted = array.sort do |x, y| 
    if x[:accepts] == y[:accepts] 
    0 
    elsif x[:accepts] == true 
    -1 
    elsif x[:accepts] == false 
    1 
    end 
end 

इस तरह है कि मैं पैदावार है:

5 - सच
3 - सच
2 - झूठी
4 - झूठी
1 - झूठी उपज के लिए

मैं इसे की जरूरत है :

3 - सत्य
5 - tr ue
1 - झूठी
2 - झूठी
4 - झूठी

उत्तर

7

यह काम करता है:

array.sort{|a,b| (a[:accepts] == b[:accepts]) ? ((a[:id] < b[:id]) ? -1 : 1) : (a[:accepts] ? -1 : 1)} 
+0

बिंगो! धन्यवाद एक लाख फिलिप! – Nick

+0

आपका स्वागत है! ;) – Philip

+0

मुझे इस समाधान को पसंद नहीं है क्योंकि यह मूल आदेश नहीं रखता है जिसे लेखक द्वारा एक आवश्यकता के रूप में वर्णित किया गया था। इसके बजाय इसका अर्थ है कि 'आईडी' पहले से ही आदेश दिया गया है और इसे एक सहायक कुंजी के रूप में दुरुपयोग करता है। – hurikhan77

1
array = [{:id => 1, :accepts => false}, 
     {:id => 2, :accepts => false}, 
     {:id => 3, :accepts => true}, 
     {:id => 4, :accepts => false}, 
     {:id => 5, :accepts => true}] 

sorted = array.sort do |x, y| 
    if x[:accepts]^y[:accepts] 
     x[:accepts] ? -1 : 1 
    else 
     x[:id] <=> y[:id] 
    end 
end 

puts sorted 

या ^ के बजाय !=, यदि आप चाहें तो।

+3

क्रूर दुनिया ... कोई भी नहीं जानता '<=> ' – Nakilon

0

आप इस प्रकार :id कुंजी पर एक अतिरिक्त जांच जोड़ सकता है अगर :accepts बराबर है,:

array = [{:id => 1, :accepts => false}, 
    {:id => 2, :accepts => false}, 
    {:id => 3, :accepts => true}, 
    {:id => 4, :accepts => false}, 
    {:id => 5, :accepts => true}] 

sorted = array.sort do |x, y| 
    if x[:accepts] == y[:accepts] 
    if x[:id] == y[:id] 
     0 
    elsif x[:id] > y[:id] 
     1 
    elsif x[:id] < y[:id] 
     -1 
    end 
  elsif x[:accepts] == true 
    -1 
  elsif x[:accepts] == false 
    1 
  end 
end 
+0

ऐसा कर सकता है। – Nick

0
a.sort_by { |x| (x[:accepts] ? 0 : 99999) + x[:id] } 

अद्यतन: ठीक है, जाहिर है, इसके लिए x[:id].respond_to? "+" की आवश्यकता है और इसके अतिरिक्त स्थिरांक के सापेक्ष इसकी सीमा पर प्रतिबंध हैं।

हालांकि, यह सबसे छोटा और शायद सबसे तेज़ उत्तर है, अगर यह स्पष्ट रूप से सबसे संदिग्ध भी है।

वास्तव में महत्वपूर्ण सबक यह है कि यह दर्शाता है कि Array (या जो कुछ भी) से परे देखना चाहिए और में Enumerable देखें। ये प्रश्न और उनके दर्शक अक्सर "" के उत्तर के बाद अक्सर रूबी के बारे में मुझे क्या सीखना चाहिए, मुझे संदेह है कि अन्य तरीके "हैं।

इस सुलझाने के लिए एक अच्छा तरीका है (वैसे यह संदेहास्पद है) इस उत्तर #sort_by और बस डॉक्स #sort_by के लिए खोजने (यह सरणी में नहीं है) अभी शुरुआत करने के लिए एक छोटी लेकिन महत्वपूर्ण सबक सिखा देगा पता चलता है या न करें।

+1

यह इस तरह का बहुत बुरा और गूंगा उत्तर है जो सिर्फ स्मार्ट दिखता है। शुरुआती लोगों के लिए उपयुक्त नहीं है जो एक नई भाषा में अपने पहले कदमों के लिए मदद चाहते हैं - खासकर किसी भी स्पष्टीकरण की अनुपस्थिति में। – hurikhan77

+1

यह डाउनवॉटेड उत्तर किस तरह से @glenn mcdonald के उल्लिखित उत्तर से अलग है? दोनों जवाब स्पष्टीकरण के साथ कर सकते हैं, यह सच है, और ग्लेन थोड़ा बेहतर है, लेकिन यह _that_ खराब नहीं है। –

+2

"बहुत बुरी और गूंगा" एक बहुत ही सहयोगी टिप्पणी नहीं है, लेकिन निष्पक्ष रूप से बोलते हुए मुझे लगता है कि इस में तीन पहचान योग्य दोष हैं जो इसे कम से कम आदर्श सुझाव देते हैं। सबसे स्पष्ट रूप से, यह मानता है कि आईड्स 99 999 से अधिक नहीं मिलता है। यह अब या बाद में गलत हो सकता है। दूसरा, 99 999 जैसे जादू मूल्य सामान्य रूप से स्पष्टता और समझ के दुश्मन हैं, और इस प्रकार रखरखाव के हैं। और तीसरा, यह संस्करण अतिरिक्त उपयोग करता है, जो कार्यात्मक रूप से अप्रासंगिक है, और अगर बाद में ids तारों, या ऋणात्मक संख्याओं या कुछ और में बदल जाता है तो टूट जाएगा। –

14

इन चीजों के लिए sort_by का उपयोग करें, sort नहीं!

array.sort_by {|h| [h[:accepts] ? 0 : 1,h[:id]]} 
+0

नाइस बदल गया। धीमा (मुझे लगता है), लेकिन ठंडा। – Nakilon

+0

@ नाकिलॉन, मेरे बॉक्स पर और एमआरआई 1.8.7 का उपयोग करके, ग्लेन का कोड आपके कोड के आधे से थोड़ा समय लेता है। –

+0

मैं यह नहीं कह रहा हूं कि ऐसे मामले नहीं हैं जहां 'sort'by' से' sort' तेज है, लेकिन मैंने कभी खुद का सामना नहीं किया है। आमतौर पर 'sort_by' काफी तेज़ है। और इससे भी महत्वपूर्ण बात यह है कि एक ऐसा कार्य लिखना जो एक यूनरी सॉर्ट-वैल्यू उत्पन्न करता है * बाइनरी तुलना के मामलों के समूह से हमेशा * साफ * स्पष्ट और स्पष्ट होता है। निजी तौर पर, मैं उन मामलों के लिए 'सॉर्ट' आरक्षित करता हूं जहां मुझे वास्तव में तुलनाओं की जोड़ी के गुणों के अनुसार अलग-अलग * तर्क * करने की आवश्यकता होती है। जैसे कि अगर मुझे दोनों संख्याएं हैं, या तारीख के अनुसार यदि वे दोनों तिथियां हैं, या स्ट्रिंगवॉइड अन्यथा हैं, तो स्ट्रिंग्स की तुलनात्मक रूप से तुलना करने की आवश्यकता है ... –

0

ऐसा इसलिए है क्योंकि रूबी 1.8 में सॉर्टिंग।7 स्थिर नहीं है

सभी आप अपनी तरह ब्लॉक करने की जरूरत है 0 वापस नहीं:

sorted = array.sort do |x, y| 
    if x[:accepts] == y[:accepts] 
    x[:id] <=> y[:id] # not 0 
    elsif x[:accepts] 
    -1 
    else 
    1 
    end 
end 

(कोई स्पष्ट रूप से एक बूलियन तुलना करने के लिए की जरूरत true और false)

1

ठीक है, आपके प्रश्न से मैं आपको वास्तव में :accepts मान से परिणामों को समूहित करना चाहता हूं और दोनों परिणाम एक सरणी में वापस सेट करना चाहता हूं। यह करने के लिए मेरे समाधान किया गया है जाएगा:

array.select {|where| where[:accepts] } | array.reject {|where| where[:accepts] } 
# => [{:accepts=>true, :id=>3}, 
#  {:accepts=>true, :id=>5}, 
#  {:accepts=>false, :id=>1}, 
#  {:accepts=>false, :id=>2}, 
#  {:accepts=>false, :id=>4}] 

यह :id कुंजी पर किसी भी प्रकार जिसका अर्थ बिना मूल आदेश को बनाए रखेगा। इसका मतलब है कि आपको ऑर्डर को सुरक्षित रखने के लिए एक सहायक कुंजी की आवश्यकता नहीं होगी, और आप पहुंचे गए डेटा के बावजूद परिणाम पर ऑर्डर को सुरक्षित रख सकते हैं।

यह भी उपयोगी हो सकता है (और शायद वास्तव में आप आगे के मूल्यांकन के लिए क्या जरूरत है):

array.group_by {|where| where[:accepts] } 
# => {false=>[{:accepts=>false, :id=>1}, 
#    {:accepts=>false, :id=>2}, 
#    {:accepts=>false, :id=>4}], 
#  true=>[{:accepts=>true, :id=>3}, 
#    {:accepts=>true, :id=>5}]} 

फिर से, कोई कृत्रिम प्रकार शामिल ... group_by 1.8.7 में नया है।

पीएस: यदि आप नहीं चाहते हैं कि पहला कोड स्निपेट आपके सरणी से डुप्लीकेट हटा दें, बार ऑपरेटर को प्लस ऑपरेटर के साथ प्रतिस्थापित करें। "|" theory of sets (संघ) के अनुसार दो सेट विलय करते हैं जबकि "+" दो सेटों को जोड़ता है (परिणाम वास्तव में एक सेट नहीं बल्कि एक सादा सरणी है)।

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