পাইথনে সংস্করণ সংখ্যা তুলনা


99

আমি লিখতে চান cmp-একটি ফাংশন যা দুই সংস্করণ সংখ্যা এবং আয় তুলনা -1, 0অথবা 1তাদের তুলনায় valuses উপর ভিত্তি করে।

  • -1সংস্করণ A সংস্করণ বি এর চেয়ে পুরানো হলে ফিরে আসুন
  • 0সংস্করণ A এবং B সমান হলে ফিরে আসুন
  • 1সংস্করণ A সংস্করণ বি এর চেয়ে নতুন হলে ফিরে আসুন

প্রতিটি অনুচ্ছেদটি একটি সংখ্যা হিসাবে ব্যাখ্যা করার কথা, সুতরাং 1.10> 1.1।

পছন্দসই ফাংশন আউটপুট হয়

mycmp('1.0', '1') == 0
mycmp('1.0.0', '1') == 0
mycmp('1', '1.0.0.1') == -1
mycmp('12.10', '11.0.0.0.0') == 1
...

এবং এখানে আমার বাস্তবায়ন, উন্নতির জন্য উন্মুক্ত:

def mycmp(version1, version2):
    parts1 = [int(x) for x in version1.split('.')]
    parts2 = [int(x) for x in version2.split('.')]

    # fill up the shorter version with zeros ...
    lendiff = len(parts1) - len(parts2)
    if lendiff > 0:
        parts2.extend([0] * lendiff)
    elif lendiff < 0:
        parts1.extend([0] * (-lendiff))

    for i, p in enumerate(parts1):
        ret = cmp(p, parts2[i])
        if ret: return ret
    return 0

আমি পাইথন ২.৪.৫ বিটিডাব্লু ব্যবহার করছি। (আমার কর্মক্ষেত্রে ইনস্টল করা ...)।

আপনি ব্যবহার করতে পারেন এখানে একটি ছোট 'টেস্ট স্যুট'

assert mycmp('1', '2') == -1
assert mycmp('2', '1') == 1
assert mycmp('1', '1') == 0
assert mycmp('1.0', '1') == 0
assert mycmp('1', '1.000') == 0
assert mycmp('12.01', '12.1') == 0
assert mycmp('13.0.1', '13.00.02') == -1
assert mycmp('1.1.1.1', '1.1.1.1') == 0
assert mycmp('1.1.1.2', '1.1.1.1') == 1
assert mycmp('1.1.3', '1.1.3.000') == 0
assert mycmp('3.1.1.0', '3.1.2.10') == -1
assert mycmp('1.1', '1.10') == -1

কোনও উত্তর নয় বরং একটি পরামর্শ - সংস্করণ নম্বর তুলনা (মূলত, অ-সংখ্যা ও সংখ্যার অংশগুলি বাছাই করে) এর জন্য ডিবিয়ান অ্যালগরিদম প্রয়োগ করা উপযুক্ত। অ্যালগরিদমটি এখানে বর্ণিত হয়েছে ("স্ট্রিংগুলি বাম থেকে ডানে তুলনা করা হয়" -এ শুরু করে)।
hobbs

ব্লারঘ মন্তব্যে সমর্থিত মার্কডাউনের উপসেটটি আমাকে কখনও বিভ্রান্ত করতে ব্যর্থ হয়। লিঙ্কটি যাইহোক কাজ করে, এমনকি এটি নির্বোধ বলে মনে হয়।
hobbs

ভবিষ্যতে পাঠকদের যদি ব্যবহারকারী-এজেন্ট সংস্করণ পার্সিংয়ের জন্য এটির প্রয়োজন হয় তবে আমি একটি ডেডিকেটেড লাইব্রেরিটিকে wideতিহাসিক বৈচিত্র হিসাবে এটি প্রস্তাব করি।
জেমস ব্রডহেড


4
যদিও এখানে প্রশ্নটি পুরান, তবুও এটি প্রদর্শিত হয় যে এই অন্যান্য প্রশ্নটি আধ্যাত্মিক হিসাবে অভিষিক্ত হয়েছে, অনেক হিসাবে, অনেকগুলি প্রশ্নটির নকল হিসাবে বন্ধ রয়েছে।
জন ওয়াই

উত্তর:


37

স্ট্রিংয়ের অনিচ্ছাকৃত অংশটি সরিয়ে ফেলুন (শূন্য ও বিন্দু অনুসরণ করে) এবং তারপরে সংখ্যার তালিকার তুলনা করুন।

import re

def mycmp(version1, version2):
    def normalize(v):
        return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
    return cmp(normalize(version1), normalize(version2))

এটি প্যার উইসল্যান্ডারের মতো একই পদ্ধতি, তবে আরও কিছুটা কমপ্যাক্ট:

এখানে কিছু পরীক্ষা দেওয়া আছে, " বাশের মধ্যে বিন্দু দ্বারা বিভক্ত সংস্করণ বিন্যাসে দুটি স্ট্রিং কীভাবে তুলনা করবেন? ":

assert mycmp("1", "1") == 0
assert mycmp("2.1", "2.2") < 0
assert mycmp("3.0.4.10", "3.0.4.2") > 0
assert mycmp("4.08", "4.08.01") < 0
assert mycmp("3.2.1.9.8144", "3.2") > 0
assert mycmp("3.2", "3.2.1.9.8144") < 0
assert mycmp("1.2", "2.1") < 0
assert mycmp("2.1", "1.2") > 0
assert mycmp("5.6.7", "5.6.7") == 0
assert mycmp("1.01.1", "1.1.1") == 0
assert mycmp("1.1.1", "1.01.1") == 0
assert mycmp("1", "1.0") == 0
assert mycmp("1.0", "1") == 0
assert mycmp("1.0", "1.0.1") < 0
assert mycmp("1.0.1", "1.0") > 0
assert mycmp("1.0.2.0", "1.0.2") == 0

4
আমি ভয় করি এটি কাজ করবে না, rstrip(".0")"1.0.10" তে ".10" "" .1 "তে পরিবর্তিত হবে।
রেডগ্লাইফ

দুঃখিত, তবে আপনার ফাংশন সহ: mycmp ('1.1', '1.10') == 0
জোহানেস চারারা

রেজেক্স ব্যবহারের সাথে, উপরে উল্লিখিত সমস্যাটি স্থির হয়েছে।
gnud

এখন আপনি অন্যের কাছ থেকে সমস্ত ভাল ধারণাগুলি আপনার সমাধানে একীভূত করেছেন ... :- পি তবুও, আমি সর্বোপরি যা করব তা এটি অনেকটাই। আমি এই উত্তর গ্রহণ করব। ধন্যবাদ, সবাই
জোহানেস চারারা

4
নোট সিএমপি () পাইথন 3: ডকস.পাইথন.আর.৩.০
ডোমিনিক

281

পাইথনের ব্যবহার সম্পর্কে কীভাবে distutils.version.StrictVersion?

>>> from distutils.version import StrictVersion
>>> StrictVersion('10.4.10') > StrictVersion('10.4.9')
True

সুতরাং আপনার cmpফাংশন জন্য:

>>> cmp = lambda x, y: StrictVersion(x).__cmp__(y)
>>> cmp("10.4.10", "10.4.11")
-1

আপনি যদি আরও জটিল যে সংস্করণ সংখ্যাগুলি তুলনা করতে চান distutils.version.LooseVersionতবে আরও দরকারী হবে তবে কেবল একই ধরণের তুলনা করতে ভুলবেন না।

>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion('1.4c3') > LooseVersion('1.3')
True
>>> LooseVersion('1.4c3') > StrictVersion('1.3')  # different types
False

LooseVersion সর্বাধিক বুদ্ধিমান সরঞ্জাম নয়, এবং সহজেই ট্রিক করা যায়:

>>> LooseVersion('1.4') > LooseVersion('1.4-rc1')
False

এই জাতের সাথে সাফল্য পেতে, আপনাকে স্ট্যান্ডার্ড লাইব্রেরির বাইরে যেতে হবে এবং সেটআপলগুলির পার্সিং ইউটিলিটিটি ব্যবহার করতে হবে parse_version

>>> from pkg_resources import parse_version
>>> parse_version('1.4') > parse_version('1.4-rc2')
True

সুতরাং আপনার নির্দিষ্ট ব্যবহারের ক্ষেত্রে নির্ভর করে আপনাকে সিদ্ধান্ত নিতে হবে যে বিল্টিন distutilsসরঞ্জামগুলি যথেষ্ট কিনা , বা নির্ভরতা হিসাবে যুক্ত করার জন্য যদি এটির ওয়্যারেন্টেড থাকে setuptools


4
ইতিমধ্যে যা আছে কেবল তা ব্যবহার করার জন্য সর্বাধিক বোধ করা হচ্ছে বলে মনে হয় :)
প্যাট্রিক উল্ফ

4
চমৎকার! উত্সটি পড়ে আপনি কী এটিকে বের করেছিলেন? আমি distutils.version এর জন্য কোথাও দস্তাবেজগুলি খুঁজে পাচ্ছি না: - /
অ্যাডাম

4
যে কোনও সময় আপনি ডকুমেন্টেশন খুঁজে না পেয়ে প্যাকেজটি আমদানির চেষ্টা করুন এবং সহায়তা () ব্যবহার করুন।
০১:০12 এ

13
তবে সচেতন থাকুন, StrictVersion কেবল তিনটি সংস্করণ পর্যন্ত কাজ করে। এটি যেমন জিনিস ব্যর্থ 0.4.3.6!

6
distributeএই উত্তরের প্রতিটি উদাহরণ প্রতিস্থাপন করা উচিত setuptools, যা pkg_resourcesপ্যাকেজটির সাথে বান্ডিল হয়ে আসে এবং তখন থেকে ... পছন্দ হয়েছে । একইভাবে, এই হল সরকারী ডকুমেন্টেশন জন্য pkg_resources.parse_version()ফাংশন একত্রিত setuptools
সিসিল কারি

30

হয় পুনঃব্যবহারের এই ইনস্ট্যান্সের মধ্যে কমনীয়তা বিবেচনা? :)

# pkg_resources is in setuptools
# See http://peak.telecommunity.com/DevCenter/PkgResources#parsing-utilities
def mycmp(a, b):
    from pkg_resources import parse_version as V
    return cmp(V(a),V(b))

7
হুম, আপনি কোথা থেকে পাবেন তা ব্যাখ্যা না করে যখন আপনি স্ট্যান্ডার্ড লাইব্রেরির বাইরে কিছু উল্লেখ করেন তখন এটি মার্জিত হয় না। আমি URL টি অন্তর্ভুক্ত করার জন্য একটি সম্পাদনা জমা দিয়েছি। ব্যক্তিগতভাবে আমি ডিস্টিওলেটগুলি ব্যবহার করতে পছন্দ করি - এত সহজ কোনও কাজের জন্য তৃতীয় পক্ষের সফ্টওয়্যারটি টানতে চেষ্টা করার মতো মনে হয় না।
অ্যাডাম স্পায়ার্স

4
@ অ্যাডাম- স্পায়ারস? এমনকি আপনি কি ভাষ্যটি পড়েছেন? pkg_resourcesএকটি- setuptoolsব্যান্ডেল্ড প্যাকেজ। যেহেতু setuptoolsসমস্ত পাইথন ইনস্টলেশনগুলিতে কার্যকরভাবে বাধ্যতামূলক, pkg_resourcesকার্যকরভাবে সর্বত্র পাওয়া যায়। এটি বলেছিল, distutils.versionসাব - প্যাকেজটিও দরকারী - উচ্চ-স্তরের pkg_resources.parse_version()ক্রিয়াকলাপের তুলনায় যথেষ্ট কম বুদ্ধিমান । কোনটি আপনার উত্তোলন করা উচিত তা সংস্করণের স্ট্রিংগুলিতে আপনি কত ডিগ্রি পাগলের প্রত্যাশা করে তার উপর নির্ভর করে।
সিসিল কারি

@ সিসিলকিউরি হ্যাঁ অবশ্যই আমি মন্তব্যটি (অ্যারি) পড়েছি, এ কারণেই আমি এটিকে আরও ভাল করার জন্য এটি সম্পাদনা করেছি, এবং তারপরে বলেছি যে আমার ছিল। সম্ভবত আপনি আমার বক্তব্যের সাথে একমত নন setuptoolsযেটি স্ট্যান্ডার্ড লাইব্রেরির বাইরের, এবং পরিবর্তে distutils এই ক্ষেত্রে আমার বর্ণিত পছন্দের সাথে । সুতরাং আপনি "কার্যকরভাবে বাধ্যতামূলক" বলতে আসলে কী বোঝায়, এবং দয়া করে আপনি প্রমাণ প্রদান করতে পারেন যে আমি যখন এই মন্তব্যটি লিখেছিলাম 4.5 বছর আগে এটি "কার্যকরভাবে বাধ্যতামূলক" ছিল?
অ্যাডাম স্পায়ার্স

12

সংস্করণ টিউপসগুলিতে পুনরাবৃত্তি করার দরকার নেই। তালিকাগুলিতে এবং তুলনায় তুলনায় অপারেটরটি ইতিমধ্যে আপনি যেমন চান ঠিক তেমন কাজ করে। আপনার কেবল সামঞ্জস্যিত দৈর্ঘ্যের সংস্করণ তালিকাগুলি প্রসারিত করতে হবে। পাইথন ২.6 এর সাহায্যে আপনি ক্রমগুলি প্যাড করতে izip_longest ব্যবহার করতে পারেন।

from itertools import izip_longest
def version_cmp(v1, v2):
    parts1, parts2 = [map(int, v.split('.')) for v in [v1, v2]]
    parts1, parts2 = zip(*izip_longest(parts1, parts2, fillvalue=0))
    return cmp(parts1, parts2)

নিম্ন সংস্করণ সহ, কিছু মানচিত্র হ্যাকারি প্রয়োজন।

def version_cmp(v1, v2):
    parts1, parts2 = [map(int, v.split('.')) for v in [v1, v2]]
    parts1, parts2 = zip(*map(lambda p1,p2: (p1 or 0, p2 or 0), parts1, parts2))
    return cmp(parts1, parts2)

দুর্দান্ত, তবে গদ্যের মতো কোড পড়তে পারেন না এমন কারও পক্ষে বোঝা শক্ত। :) ঠিক আছে, আমি ধরে নিচ্ছি আপনি কেবল পাঠযোগ্যতার ব্যয়ে সমাধানটি সংক্ষিপ্ত করতে পারবেন ...
জোহানেস চারারা

10

এটি আপনার পরামর্শের চেয়ে কিছুটা কমপ্যাক্ট। শূন্যের সাথে সংক্ষিপ্ত সংস্করণটি পূরণ করার পরিবর্তে, আমি বিভাজনের পরে সংস্করণ তালিকাগুলি থেকে পিছনের জিরোগুলি সরিয়ে ফেলছি।

def normalize_version(v):
    parts = [int(x) for x in v.split(".")]
    while parts[-1] == 0:
        parts.pop()
    return parts

def mycmp(v1, v2):
    return cmp(normalize_version(v1), normalize_version(v2))

ভাল এক, thx। তবে আমি এখনও এক বা দ্বি-লাইনারের জন্য প্রত্যাশা করছি ...;)
জোহানেস চারারা

4
+1 @ জেলিবিয়ান: দ্বি-লাইনার রক্ষণাবেক্ষণ এবং পঠনযোগ্যতার জন্য সর্বদা সেরা নয়, এটি একই সাথে খুব স্পষ্ট এবং কমপ্যাক্ট কোড, এছাড়াও, mycmpআপনার কোডের প্রয়োজন হলে আপনি অন্য কোডগুলির জন্য পুনরায় ব্যবহার করতে পারেন ।
রেডগ্লাইফ

@ রেডগ্লাইফ: আপনি একটি পয়েন্ট পেয়েছেন। "একটি পঠনযোগ্য দ্বি-লাইনার" বলা উচিত ছিল। :)
জোহানেস চারারা

হাই @ প্যার উইসল্যান্ডার, আমি যখন লাইটকোড সমস্যাটিতে একই সমস্যাটি সমাধান করার জন্য এই সমাধানটি ব্যবহার করি তখন আমি "তালিকা সূচকের বাইরে" বলে লুপে একটি ত্রুটি পাই। আপনি দয়া করে সাহায্য করতে পারেন কেন এটি ঘটে? সমস্যাটি এখানে: leetcode.com/explore/interview/card/amazon/76/array-and-strings/…
YouHaveaBigEgo

7

ট্রেলিং .0এবং .00রেজেক্সের সাথে সরান , splitএবং cmpফাংশনটি ব্যবহার করুন যা অ্যারের সাথে সঠিকভাবে তুলনা করে:

def mycmp(v1,v2):
 c1=map(int,re.sub('(\.0+)+\Z','',v1).split('.'))
 c2=map(int,re.sub('(\.0+)+\Z','',v2).split('.'))
 return cmp(c1,c2)

এবং, অবশ্যই, আপনি যদি লাইনগুলিতে কিছু মনে না করেন তবে আপনি এটি ওয়ান-লাইনারে রূপান্তর করতে পারেন।


2
def compare_version(v1, v2):
    return cmp(*tuple(zip(*map(lambda x, y: (x or 0, y or 0), 
           [int(x) for x in v1.split('.')], [int(y) for y in v2.split('.')]))))

এটি ওয়ান লাইনার (সামর্থ্যের জন্য বিভক্ত)। পঠনযোগ্য সম্পর্কে নিশ্চিত নয় ...


4
হ্যাঁ! এবং আরও সঙ্কুচিত ( tupleবিটিডব্লির প্রয়োজন নেই):cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
পল

2
from distutils.version import StrictVersion
def version_compare(v1, v2, op=None):
    _map = {
        '<': [-1],
        'lt': [-1],
        '<=': [-1, 0],
        'le': [-1, 0],
        '>': [1],
        'gt': [1],
        '>=': [1, 0],
        'ge': [1, 0],
        '==': [0],
        'eq': [0],
        '!=': [-1, 1],
        'ne': [-1, 1],
        '<>': [-1, 1]
    }
    v1 = StrictVersion(v1)
    v2 = StrictVersion(v2)
    result = cmp(v1, v2)
    if op:
        assert op in _map.keys()
        return result in _map[op]
    return result

version_compare"=" বাদে পিএইচপি জন্য প্রয়োগ করুন । কারণ এটি অস্পষ্ট।


2

পাইথনে তালিকাগুলি তুলনীয়, সুতরাং যদি কেউ সংখ্যাকে পূর্ণসংখ্যার প্রতিনিধিত্বকারী স্ট্রিংগুলিকে রূপান্তর করে তবে প্রাথমিক পাইথন তুলনা সাফল্যের সাথে ব্যবহার করা যেতে পারে।

আমার এই পদ্ধতির কিছুটা প্রসারিত করার দরকার ছিল কারণ আমি পাইথন 3 এক্স ব্যবহার করি যেখানে cmpফাংশনটির আর অস্তিত্ব নেই। আমার সাথে অনুকরণ cmp(a,b)করতে হয়েছিল (a > b) - (a < b)। এবং, সংস্করণ সংখ্যাগুলি মোটেও পরিষ্কার নয় এবং এতে সমস্ত ধরণের অন্যান্য বর্ণমালা থাকতে পারে। কিছু ক্ষেত্রে আছে যখন ফাংশনটি অর্ডার বলতে না পারে যাতে এটি ফিরে আসে False(প্রথম উদাহরণটি দেখুন)।

সুতরাং আমি প্রশ্নটি পুরানো হলেও ইতিমধ্যে উত্তর দিচ্ছি, কারণ এটি কারওর জীবনে কয়েক মিনিট বাঁচাতে পারে।

import re

def _preprocess(v, separator, ignorecase):
    if ignorecase: v = v.lower()
    return [int(x) if x.isdigit() else [int(y) if y.isdigit() else y for y in re.findall("\d+|[a-zA-Z]+", x)] for x in v.split(separator)]

def compare(a, b, separator = '.', ignorecase = True):
    a = _preprocess(a, separator, ignorecase)
    b = _preprocess(b, separator, ignorecase)
    try:
        return (a > b) - (a < b)
    except:
        return False

print(compare('1.0', 'beta13'))    
print(compare('1.1.2', '1.1.2'))
print(compare('1.2.2', '1.1.2'))
print(compare('1.1.beta1', '1.1.beta2'))

2

আপনি যদি কোনও বাহ্যিক নির্ভরতা টানতে না চান তবে পাইথন ৩.x এর জন্য লেখা আমার প্রচেষ্টা is

rc, rel(এবং সম্ভবত একটি যোগ করতে পারে c) "রিলিজ প্রার্থী" হিসাবে বিবেচিত হয় এবং সংস্করণ সংখ্যাটি দুটি ভাগে ভাগ করে এবং যদি দ্বিতীয় অংশের মান না পাওয়া যায় তবে উচ্চ (999) থাকে। অন্য বর্ণগুলি একটি বিভাজন তৈরি করে এবং বেস -36 কোডের মাধ্যমে সাব-নম্বর হিসাবে ডিল করা হয়।

import re
from itertools import chain
def compare_version(version1,version2):
    '''compares two version numbers
    >>> compare_version('1', '2') < 0
    True
    >>> compare_version('2', '1') > 0
    True
    >>> compare_version('1', '1') == 0
    True
    >>> compare_version('1.0', '1') == 0
    True
    >>> compare_version('1', '1.000') == 0
    True
    >>> compare_version('12.01', '12.1') == 0
    True
    >>> compare_version('13.0.1', '13.00.02') <0
    True
    >>> compare_version('1.1.1.1', '1.1.1.1') == 0
    True
    >>> compare_version('1.1.1.2', '1.1.1.1') >0
    True
    >>> compare_version('1.1.3', '1.1.3.000') == 0
    True
    >>> compare_version('3.1.1.0', '3.1.2.10') <0
    True
    >>> compare_version('1.1', '1.10') <0
    True
    >>> compare_version('1.1.2','1.1.2') == 0
    True
    >>> compare_version('1.1.2','1.1.1') > 0
    True
    >>> compare_version('1.2','1.1.1') > 0
    True
    >>> compare_version('1.1.1-rc2','1.1.1-rc1') > 0
    True
    >>> compare_version('1.1.1a-rc2','1.1.1a-rc1') > 0
    True
    >>> compare_version('1.1.10-rc1','1.1.1a-rc2') > 0
    True
    >>> compare_version('1.1.1a-rc2','1.1.2-rc1') < 0
    True
    >>> compare_version('1.11','1.10.9') > 0
    True
    >>> compare_version('1.4','1.4-rc1') > 0
    True
    >>> compare_version('1.4c3','1.3') > 0
    True
    >>> compare_version('2.8.7rel.2','2.8.7rel.1') > 0
    True
    >>> compare_version('2.8.7.1rel.2','2.8.7rel.1') > 0
    True

    '''
    chn = lambda x:chain.from_iterable(x)
    def split_chrs(strings,chars):
        for ch in chars:
            strings = chn( [e.split(ch) for e in strings] )
        return strings
    split_digit_char=lambda x:[s for s in re.split(r'([a-zA-Z]+)',x) if len(s)>0]
    splt = lambda x:[split_digit_char(y) for y in split_chrs([x],'.-_')]
    def pad(c1,c2,f='0'):
        while len(c1) > len(c2): c2+=[f]
        while len(c2) > len(c1): c1+=[f]
    def base_code(ints,base):
        res=0
        for i in ints:
            res=base*res+i
        return res
    ABS = lambda lst: [abs(x) for x in lst]
    def cmp(v1,v2):
        c1 = splt(v1)
        c2 = splt(v2)
        pad(c1,c2,['0'])
        for i in range(len(c1)): pad(c1[i],c2[i])
        cc1 = [int(c,36) for c in chn(c1)]
        cc2 = [int(c,36) for c in chn(c2)]
        maxint = max(ABS(cc1+cc2))+1
        return base_code(cc1,maxint) - base_code(cc2,maxint)
    v_main_1, v_sub_1 = version1,'999'
    v_main_2, v_sub_2 = version2,'999'
    try:
        v_main_1, v_sub_1 = tuple(re.split('rel|rc',version1))
    except:
        pass
    try:
        v_main_2, v_sub_2 = tuple(re.split('rel|rc',version2))
    except:
        pass
    cmp_res=[cmp(v_main_1,v_main_2),cmp(v_sub_1,v_sub_2)]
    res = base_code(cmp_res,max(ABS(cmp_res))+1)
    return res


import random
from functools import cmp_to_key
random.shuffle(versions)
versions.sort(key=cmp_to_key(compare_version))

1

সমাধান পড়া সবচেয়ে কঠিন, তবুও একটি ওয়ান-লাইনার! এবং পুনরুক্তিকারী দ্রুত ব্যবহার করতে।

next((c for c in imap(lambda x,y:cmp(int(x or 0),int(y or 0)),
            v1.split('.'),v2.split('.')) if c), 0)

এটি পাইথন 2.6 এবং 3 এর জন্য +


1

আমি দেবিয়ান প্যাকেজ সংস্করণটির স্ট্রিং পার্স করতে এবং তুলনা করতে সক্ষম হয়েছি। দয়া করে লক্ষ্য করুন যে এটি অক্ষরের বৈধতা সহকারে কঠোর নয়।

এটি পাশাপাশি সহায়ক হতে পারে:

#!/usr/bin/env python

# Read <https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version> for further informations.

class CommonVersion(object):
    def __init__(self, version_string):
        self.version_string = version_string
        self.tags = []
        self.parse()

    def parse(self):
        parts = self.version_string.split('~')
        self.version_string = parts[0]
        if len(parts) > 1:
            self.tags = parts[1:]


    def __lt__(self, other):
        if self.version_string < other.version_string:
            return True
        for index, tag in enumerate(self.tags):
            if index not in other.tags:
                return True
            if self.tags[index] < other.tags[index]:
                return True

    @staticmethod
    def create(version_string):
        return UpstreamVersion(version_string)

class UpstreamVersion(CommonVersion):
    pass

class DebianMaintainerVersion(CommonVersion):
    pass

class CompoundDebianVersion(object):
    def __init__(self, epoch, upstream_version, debian_version):
        self.epoch = epoch
        self.upstream_version = UpstreamVersion.create(upstream_version)
        self.debian_version = DebianMaintainerVersion.create(debian_version)

    @staticmethod
    def create(version_string):
        version_string = version_string.strip()
        epoch = 0
        upstream_version = None
        debian_version = '0'

        epoch_check = version_string.split(':')
        if epoch_check[0].isdigit():
            epoch = int(epoch_check[0])
            version_string = ':'.join(epoch_check[1:])
        debian_version_check = version_string.split('-')
        if len(debian_version_check) > 1:
            debian_version = debian_version_check[-1]
            version_string = '-'.join(debian_version_check[0:-1])

        upstream_version = version_string

        return CompoundDebianVersion(epoch, upstream_version, debian_version)

    def __repr__(self):
        return '{} {}'.format(self.__class__.__name__, vars(self))

    def __lt__(self, other):
        if self.epoch < other.epoch:
            return True
        if self.upstream_version < other.upstream_version:
            return True
        if self.debian_version < other.debian_version:
            return True
        return False


if __name__ == '__main__':
    def lt(a, b):
        assert(CompoundDebianVersion.create(a) < CompoundDebianVersion.create(b))

    # test epoch
    lt('1:44.5.6', '2:44.5.6')
    lt('1:44.5.6', '1:44.5.7')
    lt('1:44.5.6', '1:44.5.7')
    lt('1:44.5.6', '2:44.5.6')
    lt('  44.5.6', '1:44.5.6')

    # test upstream version (plus tags)
    lt('1.2.3~rc7',          '1.2.3')
    lt('1.2.3~rc1',          '1.2.3~rc2')
    lt('1.2.3~rc1~nightly1', '1.2.3~rc1')
    lt('1.2.3~rc1~nightly2', '1.2.3~rc1')
    lt('1.2.3~rc1~nightly1', '1.2.3~rc1~nightly2')
    lt('1.2.3~rc1~nightly1', '1.2.3~rc2~nightly1')

    # test debian maintainer version
    lt('44.5.6-lts1', '44.5.6-lts12')
    lt('44.5.6-lts1', '44.5.7-lts1')
    lt('44.5.6-lts1', '44.5.7-lts2')
    lt('44.5.6-lts1', '44.5.6-lts2')
    lt('44.5.6-lts1', '44.5.6-lts2')
    lt('44.5.6',      '44.5.6-lts1')

0

আরেকটি সমাধান:

def mycmp(v1, v2):
    import itertools as it
    f = lambda v: list(it.dropwhile(lambda x: x == 0, map(int, v.split('.'))[::-1]))[::-1]
    return cmp(f(v1), f(v2))

যে কেউ এটির মতো ব্যবহার করতে পারে:

import itertools as it
f = lambda v: list(it.dropwhile(lambda x: x == 0, map(int, v.split('.'))[::-1]))[::-1]
f(v1) <  f(v2)
f(v1) == f(v2)
f(v1) >  f(v2)


0

বছর পরে, তবে এই প্রশ্নটি শীর্ষে রয়েছে l

এখানে আমার সংস্করণ সাজান ফাংশন। এটি সংস্করণটি সংখ্যা এবং অ-সংখ্যা বিভাগগুলিতে বিভক্ত করে। সংখ্যাগুলিকে intবিশ্রাম হিসাবে str(তালিকা আইটেমের অংশ হিসাবে) তুলনা করা হয় ।

def sort_version_2(data):
    def key(n):
        a = re.split(r'(\d+)', n)
        a[1::2] = map(int, a[1::2])
        return a
    return sorted(data, key=lambda n: key(n))

তুলনা অপারেটরগুলির সাথে আপনি keyকাস্টম Versionধরণের ধরণের হিসাবে ফাংশনটি ব্যবহার করতে পারেন । যদি আউট সত্যিই ব্যবহার cmpকরতে চান আপনি উদাহরণ হিসাবে এটি করতে পারেন: https://stackoverflow.com/a/22490617/9935708

def Version(s):
    s = re.sub(r'(\.0*)*$', '', s)  # to avoid ".0" at end
    a = re.split(r'(\d+)', s)
    a[1::2] = map(int, a[1::2])
    return a

def mycmp(a, b):
    a, b = Version(a), Version(b)
    return (a > b) - (a < b)  # DSM's answer

টেস্ট স্যুট পাস।


-1

আমার পছন্দের সমাধান:

অতিরিক্ত শূন্যের সাথে স্ট্রিংকে প্যাডিং করা এবং চারটি প্রথম ব্যবহার করা বোঝা সহজ, কোনও রেইগেক্সের প্রয়োজন হয় না এবং ল্যাম্বডা কম বেশি পড়তে পারা যায়। আমি পঠনযোগ্যতার জন্য দুটি লাইন ব্যবহার করি, আমার জন্য কমনীয়তা স্বল্প এবং সহজ simple

def mycmp(version1,version2):
  tup = lambda x: [int(y) for y in (x+'.0.0.0.0').split('.')][:4]
  return cmp(tup(version1),tup(version2))

-1

এটি আমার সমাধান (সি তে লিখেছেন, দুঃখিত)। আমি আশা করি আপনি এটি দরকারী পাবেন

int compare_versions(const char *s1, const char *s2) {
    while(*s1 && *s2) {
        if(isdigit(*s1) && isdigit(*s2)) {
            /* compare as two decimal integers */
            int s1_i = strtol(s1, &s1, 10);
            int s2_i = strtol(s2, &s2, 10);

            if(s1_i != s2_i) return s1_i - s2_i;
        } else {
            /* compare as two strings */
            while(*s1 && !isdigit(*s1) && *s2 == *s1) {
                s1++;
                s2++;
            }

            int s1_i = isdigit(*s1) ? 0 : *s1;
            int s2_i = isdigit(*s2) ? 0 : *s2;

            if(s1_i != s2_i) return s1_i - s2_i;
        }
    }

    return 0;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.