रूबी में संस्करणों की तुलना कैसे करें?


119

कुछ संस्करणों के तार की तुलना करने और नवीनतम प्राप्त करने के लिए कोड का एक टुकड़ा कैसे लिखें?

उदाहरण के लिए तार जैसे '0.1', '0.2.1', '0.44':।


मुझे थोड़ी देर पहले निराशावादी संस्करण की कमी की तुलना करने की आवश्यकता थी, लेकिन मैं इसे करने के लिए रूबीजीम्स पर निर्भर नहीं होना चाहता था, इसलिए मैंने एक साधारण Versionवर्ग लिखा जो मुझे चाहिए वह सब कुछ: shorts.jeffkreeftmeijer.com/2014// ...
jkreeftmeijer

जवाबों:


231
Gem::Version.new('0.4.1') > Gem::Version.new('0.10.1')

14
Gem::Version...वाक्य रचना मुझे सोचा था कि मैं एक मणि स्थापित करने के लिए की आवश्यकता होगी बनाया है। लेकिन इसकी आवश्यकता नहीं थी।
गिलाउम

नोट: यह रूबी 1.x पर मेरे लिए अपरिभाषित चर 'जेम' के बारे में एक त्रुटि देता है, लेकिन रूबी 2.25. पर अपेक्षित रूप से काम करता है। मेरे मामले में मैं रूबी 1.x (2.x) नहीं होने के कारण RUBY_VERSION की जाँच कर रहा था, इसलिए मैंने बस RUBY_VERSION.split ('।') [0] == "1" जैसे जॉन हाइलैंड और डिजिटलरॉस किया।
ulvitness

5
Gem::Dependency.new(nil, '~> 1.4.5').match?(nil, '1.4.6beta4')
लेविनलेक्स

6
@uliwitness यह रूबी 1.x बनाम 2.x नहीं है; यह 1.8.x बनाम 1.9+ है। 1.8.x के माध्यम से रूबी डिफ़ॉल्ट रूप से माणिक शामिल नहीं करता है; आपको नामस्थान require 'rubygems'तक पहुंचने की आवश्यकता है Gem। हालांकि 1.9 से, यह स्वचालित रूप से शामिल है।
मार्क रीड रीड

यह वाइल्डकार्ड एनपीएम संस्करणों की तुलना करने के लिए भी काम करता है। +1
गहरा

35

यदि आपको निराशावादी संस्करण बाधाओं की जांच करने की आवश्यकता है , तो आप मणि का उपयोग कर सकते हैं :: इस तरह निर्भरता :

Gem::Dependency.new('', '~> 1.4.5').match?('', '1.4.6beta4')

1
नए संस्करणों को नाम के लिए एक स्ट्रिंग की आवश्यकता होती है। एक खाली तार ठीक काम करता है, अर्थातGem::Dependency.new('', '~> 1.4.5').match?('', '1.4.6beta4')
पीटर Wagenet

19
class Version < Array
  def initialize s
    super(s.split('.').map { |e| e.to_i })
  end
  def < x
    (self <=> x) < 0
  end
  def > x
    (self <=> x) > 0
  end
  def == x
    (self <=> x) == 0
  end
end
p [Version.new('1.2') < Version.new('1.2.1')]
p [Version.new('1.2') < Version.new('1.10.1')]

3
यहां कुछ अन्य उत्तरों की तरह, ऐसा लगता है कि आप संख्यात्मक के बजाय स्ट्रिंग तुलना कर रहे हैं, जो '0.10' और '0.4' जैसे संस्करणों की तुलना करते समय समस्याएं पैदा करेगा।
जॉन हाईलैंड

7
संक्षिप्त समाधान के लिए उत्कीर्ण जिसे रत्न स्थापित करने की आवश्यकता नहीं है।
जद।

2
इसके लायक क्या है: vers = (1..3000000).map{|x| "0.0.#{x}"}; 'ok' puts Time.now; vers.map{|v| ComparableVersion.new(v) }.sort.first; puts Time.now # 24 seconds 2013-10-29 13:36:09 -0700 2013-10-29 13:36:33 -0700 => nil puts Time.now; vers.map{|v| Gem::Version.new(v) }.sort.first; puts Time.now # 41 seconds 2013-10-29 13:36:53 -0700 2013-10-29 13:37:34 -0700 कोड ब्लॉब इसे बदसूरत बना रहा है, लेकिन मूल रूप से, यह बनाम जेम :: संस्करण का उपयोग करके लगभग दोगुना तेज है।
Shai

एक संस्करण एक सरणी नहीं है , हालांकि।
सर्जियो तुलेंत्सेव

15

आप Versionomyमणि का उपयोग कर सकते हैं ( गीथूब पर उपलब्ध ):

require 'versionomy'

v1 = Versionomy.parse('0.1')
v2 = Versionomy.parse('0.2.1')
v3 = Versionomy.parse('0.44')

v1 < v2  # => true
v2 < v3  # => true

v1 > v2  # => false
v2 > v3  # => false

4
मैंने वह देखा है, लेकिन मुझे एक साधारण बात करने के लिए 2 रत्नों का उपयोग करने की आवश्यकता है। मैं अंतिम विकल्प के रूप में इसका उपयोग करना चाहता हूं।
user239895

8
"पहिया को सुदृढ़ मत करो"। क्योंकि यह सरल है इसका मतलब यह नहीं है कि प्रोग्रामर ने काम नहीं किया और उसमें विचार किया। मणि का उपयोग करें, कोड पढ़ें, और इससे सीखें - और बड़ी और बेहतर चीजों पर आगे बढ़ें!
त्रेवोक

निर्भरता प्रबंधन और संस्करण रखरखाव एक कठिन समस्या है, 2 संस्करणों की तुलना करने के कार्य की तुलना में शायद अधिक कठिन है। मैं इस बात से पूरी तरह सहमत हूं कि इस मामले में 2 और निर्भरताएं पेश करना एक अंतिम उपाय होना चाहिए।
kkodev

10

मुझे क्या करना होगा

a1 = v1.split('.').map{|s|s.to_i}
a2 = v2.split('.').map{|s|s.to_i}

तब आप कर सकते हैं

a1 <=> a2

(और शायद सभी अन्य "सामान्य" तुलना)।

... और यदि आप एक <या >परीक्षण चाहते हैं , तो आप कर सकते हैं जैसे

(a1 <=> a2) < 0

या यदि आप इच्छुक हैं तो कुछ और फंक्शन रैपिंग करें।


1
Array.class_eval {तुलनात्मक} में सभी सरणियों <,>, आदि का जवाब देना होगा या, यदि आप केवल कुछ निश्चित सरणियों के लिए ऐसा करना चाहते हैं: a = [1, 2]; a.extend (तुलनीय)
वेन कॉनराड

4
इस समाधान के साथ मुझे जो समस्या मिली, वह यह है कि यह "1.2.0" "1.2" से बड़ा है
मारिया एस

9

Gem::Version यहाँ जाने का आसान तरीका है:

%w<0.1 0.2.1 0.44>.map {|v| Gem::Version.new v}.max.to_s
=> "0.44"

संस्करणमणि की तुलना में बहुत बेहतर है जिसे सी-एक्सटेंशन की आवश्यकता है!
डब्ल्यू। एंड्रयू लो III

मुझे नहीं लगता कि 'अधिकतम' काम करेगा .. यह 0.5 से 0.44 से अधिक होने की सूचना देगा। जो कि सेमर वर्जन की तुलना करते समय सही नहीं है।
फ्लो वू

2
ऐसा लगता है कि नवीनतम जेम :: संस्करण में तय किया गया है। 0.44 को सही ढंग से अब 0.5 से अधिक बताया गया है।
फ्लो वू

5

यदि आप इसे बिना किसी रत्नों का उपयोग किए हाथ से करना चाहते हैं, तो निम्नलिखित में से कुछ काम करना चाहिए, हालांकि यह थोड़ा सा दिखने वाला है।

versions = [ '0.10', '0.2.1', '0.4' ]
versions.map{ |v| (v.split '.').collect(&:to_i) }.max.join '.'

अनिवार्य रूप से, आप प्रत्येक संस्करण स्ट्रिंग को पूर्णांकों की एक सरणी में बदल देते हैं और फिर सरणी तुलना ऑपरेटर का उपयोग करते हैं । आप घटक चरणों को तोड़ सकते हैं ताकि कुछ का पालन करने के लिए कुछ आसान हो सके अगर यह कोड में चल रहा है तो किसी को बनाए रखने की आवश्यकता होगी।


-1

मुझे एक ही समस्या थी, मैं एक जेम-कम संस्करण तुलनित्र चाहता था, इसके साथ आया:

def compare_versions(versionString1,versionString2)
    v1 = versionString1.split('.').collect(&:to_i)
    v2 = versionString2.split('.').collect(&:to_i)
    #pad with zeroes so they're the same length
    while v1.length < v2.length
        v1.push(0)
    end
    while v2.length < v1.length
        v2.push(0)
    end
    for pair in v1.zip(v2)
        diff = pair[0] - pair[1]
        return diff if diff != 0
    end
    return 0
end
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.