バージョン番号を比較する


26

ソフトウェアを公開するとき、バージョン番号を割り当てます。また、ユーザーは一部のソフトウェアの最新バージョンに更新したい場合があります。それで、どのバージョンをより新しくすべきかを判断する時が来ました。

入力

2つのバージョン番号を文字列として入力します。

この課題の文脈では、ドットで結合されたいくつかの数字であるバージョン番号のみをサポートします。

  • バージョン番号は、数字(09)とドット(.)のみを含む文字列です。
  • ドットは、バージョン番号の最初/最後の文字ではありません。
  • ドット間には数字が必要です。2つのドットが連続して表示されることはありません。
  • バージョン番号の数値はすべて2 16未満です。

出力

入力されたバージョン番号を比較し、最初のバージョン番号が2番目のバージョン番号よりも大きい/等しい/小さいかどうかを出力します。次のプレゼンテーションのいずれかを選択できます。

  • 正の数/ゼロ/負の数を使用します。ゼロは等しいことを意味します。
  • 3つの定数の異なる値を使用します。

比較する

このセクションで説明されているアルゴリズムを実装する必要はありません。このアルゴリズムで同じ出力が得られる限り、提出は有効です。

  • バージョン番号は、ドットで結合されたいくつかの10進数です。まず、2つのバージョン番号を番号の配列に分割しました。
  • 配列の末尾にゼロを追加して、同じ長さにします。
  • 最初の項目から最後の項目までを比較します。
    • 2つの配列項目が異なる場合、数字が大きいほどバージョン番号が大きくなります
    • それらが同じ場合、次の項目の比較を続けます。
    • 配列内のすべてのアイテムが等しい場合、2つのバージョンは等しくなります。

テストケース

version1  version2  result
2         1         >
1.0.0     1         =
1.0       1.0.0     =
1.2.42    1.2.41    >
1.1.56789 1.2.0     <
1.10      1.2       >
1.20      1.150     <
18.04     18.4      =
7.010     7.8       >
1.0.0.1.0 1.00.00.2 <
00.00.01  0.0.0.1   >
0.0.1     0.1       <
42.0      4.2.0     >
999.999   999.999.1 <
2018.08.1 2018.08   >


.NETにはVersionオブジェクトがありますが、単一の文字はサポートされていません:(
Brian J

@BrianJと多くの文字に「.0」コストを追加しますか?:)
RobAu

まあ、実際には2、3、または4つの部分が必要です。それは(私が最初にあなたのアイデアを試してみましたけれども:))1.0.0.1.0テストケースに失敗したので
ブライアン・J

Windowsには、これを行う組み込み機能があると思います:StrCmpLogicalW
bace1000

回答:



6

05AB1E(レガシー)15 14 13 バイト

'.¡0ζε`.S}0K¬

出力-1 [] 1のために< = >それぞれ。

@Emignaのおかげで-1バイト。

オンラインそれを試してみたり、すべてのテストケースを確認してください

説明:

'.¡              # Split on dots
                 #  i.e. ['1.0.1.1.0','1.00.2.0']
                 #   → [['1','0','1','1','0'],['1','00','2','0']]
   0ζ            # Zip, swapping rows and columns, using '0' as filler
                 #  i.e. [['1','0','1','1','0'],['1','00','2','0']]
                 #   → [['1','1'],['0','00'],['1','2'],['1','0'],['0','0']]
     ε   }       # Map each:
      `          #  Push both values to the stack
       .S        #  And calculate the signum (1 if a>b; -1 if a<b; 0 if a==b)
                 #   i.e. [['1','1'],['0','00'],['1','2'],['1','0'],['0','0']]
                 #    → [0,0,-1,1,0]
          0K     # Remove all zeros
                 #  i.e. [0,0,-1,1,0] → [-1,1]
            ¬    # Then take the head as result
                 #  i.e. [-1,1] → -1

1
0K代わりに使用できますʒĀ}
エミグナ

@Emigna Ahもちろん..ありがとう。
ケビンCruijssen

5

R、32バイト

rank(numeric_version(scan(,"")))

オンラインでお試しください!

Rビルトインを使用する

出力1 21.5 1.52 1以下、等しい、大きいため。


これまでのところ、組み込みなしで最高:

R151142125107バイト

function(v,L=strsplit(v,'\\.'))Find(c,sign(Reduce('-',Map(as.double,Map(c,L,Map(rep,0,rev(lengths(L))))))))

オンラインでお試しください!

説明付きの展開されていないコード:

function(v){             # character vector of 2 elements as function arg;
  L=strsplit(v,'\\.')    # obtain a list of two character vectors
                         # with the separated version numbers;
  R=rev(lengths(L))      # store in vector R the lengths of the 2 vectors and reverse it;
  M1=Map(rep,0,R)        # create a list of 2 vector containing zeros
                         # repeated R[1] and R[2] times;
  M2=Map(c,L,M1)         # append to the vectors in list L the zeros in M1;
  M3=Map(as.double,M2)   # convert the character vectors in M2 to double;
  w=sign(Reduce('-',M3)  # compute the sign of element by element difference M[[1]] - M[[2]]);
  Find(c,w)            # returns the first non zero element in w, if none return NULL;
}
# N.B. as.double is necessary because "0XX" is interpreted as octal by strtoi unless 
#      we use strtoi(x,10) which is exactly the same length of as.double(x)

出力-1NULL1以下、等しい、大きいため。


オリジナルコンセプト、使用してダウンgolfed sapply[<-および%*%

R、129バイト

function(x,y=strsplit(x,"\\."),w=sign(sapply(y,function(x)strtoi("[<-"(rep(0,max(lengths(y))),seq(x),x),10))%*%c(1,-1)))w[!!w][1]

オンラインでお試しください!

これで、整数の2つの等しい長さのベクトルのリストができました。最後にReduceトリッキーな小さなw[!!w][1]形式を使用して、最初の非ゼロ要素を使用してペアワイズ差分を計算し、出力します。

出力-1NA1以下、等しい、大きいため。


印象的!クイックゴルフ:コードの最後に追加の改行
-150

...という名前の変数の数を減らします。リストの代わりにマトリックスを使用してそれを行う方法があると感じていますが、まだそれを行う方法を見つけていません。
JayCe

1
これを使用して、100バイトにscan function(a,b,d=scan(t=a,se='.'),e=scan(t=b,se='.'),f=1:max(lengths(list(d,e))),g=d[f]-e[f])g[!!g][1]
減らす

1
@mnelの100バイトソリューションには少し作業が必要です。最後の2つのテストケースで失敗します。パディングは0(暗黙的に)である必要がありNAます。答えをコミュニティWikiにしたので、修正できる人は誰でも追加できます。
ngm

1
@digEmAllは、最初に符号を計算して4バイトをゴルフし、次にを行いますFind(c,x)。これは新しいトリックだと思います。
JayCe

4

APL(Dyalog Unicode)18 17バイト

入力フォーマットをネストされた配列から行列に変更する⍤1代わりに使用するための@Adámのおかげで1バイト節約∘↑(...)¨

(⍋-⍒)(⍎¨∊∘⎕D⊆⊢)⍤1

オンラインでお試しください!

入力を正しい引数として文字の行列として受け取ります。各バージョン文字列は独自の行にあります。出力¯1 10 01 ¯1のために<=>それぞれ。

(⍎¨∊∘⎕D⊆⊢)⍤1 各行に

  • ∊∘⎕D⊆⊢ すべての数字の出現をグループ化します。つまり、分割します .

  • ⍎¨ そして、これらの各出現を数値に変換します

最初の入力が一番上の行にあり、2番目の入力が一番下にある行列に変換します0。必要に応じてsでパディングします

(⍋-⍒) そして

  • - 引く
    • 降順に並べ替える行へのインデックス
    • トップと同じですが、昇順

4

Perl 6の63の47 22バイト

{"v$^a cmp v$^b".EVAL}

オンラインでお試しください!

Perl 6には、説明にほぼ適合するバージョンタイプがあることがわかりました。これは、2つのバージョン文字列のリストを受け取りMoreSameまたはのいずれかを返す匿名コードブロックですLess

説明:

{                    }  # Anonymous code block
 "             "        # Create a string of code
  v$^a cmp v$^b         # Comparing the two versions
                .EVAL   # And EVAL it

または、47バイトの組み込みタイプなし:

{first +*,[Z<=>] map *.split('.')[^@_.ords],@_}

オンラインでお試しください!

2つの文字列を受け取りMore、2番目の文字列が大きい場合、2番目の文字列Lessが小さい場合、およびNil等しい場合に返す匿名コードブロック。

説明:

{                                             } # Anonymous code block
                 map *.split('.')          ,@_  # Split both strings by '.'
                                 [^@_.ords]     # Pad the lists by a lot
          [Z<=>]   # Zip the strings with the <=> operator
 first +*,  # Get the first value that when coerced to an int, is not 0

3

Brachylog49 40バイト

+0|{~c[H,".",T]hị;T|ị;0|0}ᵐz{h-0&t↰₀|h-}

...それでもかなり印象的ではありません。

2つの文字列のリストが必要です。positive number / zero / negative number として使用し> / = / <ます。

オンラインでお試しください!

説明

入力を分割する

で統一されていない入力が与えられた場合[0, 0]、など["1.02.0", "1.2.0.1.0"]、以下のセグメント出力[[1, "02.0"], [1, "2.0.1.0"]]

                            # unify the input with...
+0                          # : a list whose sum = 0 (output is 0)
  |{                     }ᵐ # : OR a list that when mapped...
    ~c                      # : : if the input string unifies with a list of the form...
      [H,".",T]             # : : : e.g. "1.02.0", H = "1", T = "02.0"
               hị           # : : : coerce the head to an integer
                 ;T         # : : : append the string T
                            # : : : "1.02.0" -> [1, "02.0"]
                   |ị       # : : OR it unifies with an integer
                     ;0     # : : : append 0
                            # : : : "1" -> [1, 0]
                       |0   # : : OR it unifies with 0
                            # : : : 0 -> [0]

入力の比較

たとえば、を指定[[1, "02.0"], [1, "2.0.1.0"]]する[[1, 1], ["02.0", "2.0.1.0"]]と、サブリストが圧縮され、先頭の値が比較されます([1,1])。2番目のサブリストで繰り返します。zip述語zは短いリストを循環するため、zipでwithはでzipに[0,0]等しいことに注意してください[0]。したがって、前の手順は00値を追加せずに統合します。

z             # zip the sublists
 {          } # unify the result (r) with...
  h           # : take the head of the result
   -          # : : subtract the second value from the first
    0         # : : if the difference unifies with 0...
     &t↰₀     # : : recur on the tail of r
         |h-  # : OR unify with the difference of the elements of the head
              # : (equivalent to returning early)

3

JavaScript(ES6)、73 68バイト

@redundancyのおかげで5バイト節約

入力をとして受け取ります(a)(b)。返し返します0より大きいか、のために負の整数未満

a=>b=>(a+[...b].fill`.`).split`.`.some((x,i)=>d=~b.split`.`[i]-~x)*d

オンラインでお試しください!


いいね 私が正しく理解している場合は、代入してバイトを保存することができreplacefill-両方のオペランドを数値に強制する必要があるため、のオペランドは交換されます。オンラインでお試しください!
冗長性

@冗長性良いアイデアです!(しかし、私の実装があなたが念頭に置いていたものであるかどうかは確かではありません。)
アーナウルド

あなたの意図は、a0 bよりも強い数のセグメントを含む場合、最終的にそれらの0値を循環するように0に強制可能な十分な値を追加することであると仮定しましたa。それを確実にする最短の方法はb、 '。'の長さの文字列で分割することです。に適用される既存の分割を活用するa
冗長性

3

Java(JDK 10)201 96 89バイト

java.util.Comparator.comparing(java.lang.module.ModuleDescriptor.Version::parse)::compare

オンラインでお試しください!

最初のバージョンが2番目のバージョンよりも小さい場合は負の数を返し、最初のバージョンが2番目のバージョンよりも大きく、0それらが等しい場合は正の数を返します。

うん、それはビルトインを「ただ」呼び出すための重い仕事です!

クレジット


1
試しましたが、3バイトしか削除できません
。.228

1
さらに何かを見つけた:217バイト
ケビンクルーッセン

1
たぶんそれだけでしょう。.if try-finally-checkを単純化できるようにすでに試みました。ifループ内に戻りましたt!=0; とを使用Integerしてみましたi.compare(i.valueOf(...),i.valueOf(...)); このようなジェネリックを使用してみました<T>T[]g(T s){return(T[])(s+"").replaceAll("(\\.0+)*$","").split("\\.");}。など。すべて2〜6バイト長くなります。あなた(または他の誰か)がさらに何かを見つけたら、私に知らせてください。何を知りたいですか。:)
ケビンクルーッセン

1
@KevinCruijssenいいえ、「バージョン番号のすべての数字が未満になる」ため、できません2^16。-(2 ^ 15)から2 ^ 15-1までの短い範囲。
オリビエグレゴワール

1
@KevinCruijssen 105バイト削除できました!どうやって?さて、私は組み込みを見つけました;)
オリビエグレゴワール


2

Retina 0.8.2、54バイト

\d+
$*
+`^(.)(.*=)\1
$2
(.*=|^=.*)1.*
<
.*1.*=.*
>
\.

オンラインでお試しください!リンクにはテストケースが含まれます。セパレーター値を等値出力として使用するため、便宜上ヘッダーは入力セパレーターを変換します=が、にないものを使用できます[.\d]。説明:

\d+
$*

単項に変換します。

+`^(.)(.*=)\1
$2

異なるか片側がなくなるまで、各側の最初の文字を繰り返し削除します。ゴルファーではないかもしれませんが、これはプレフィックスを一致させるよりもはるかに高速です。この時点で、文字列はいくつかの形式の1つであり、比較結果にデコードする必要があります。

  1. どちらの文字列にも 1、結果は=
  2. 左の文字列が 1結果は>
  3. 正しい文字列が 1結果は<
  4. 左の文字列が空の場合、結果は <
  5. この時点で、右側の文字列は空なので、結果は >

これについて考えるもう1つの方法は、1つの文字列にaが含まれ、もう1つの文字列がa 1で始まっていない1場合、その文字列は大きくなりますが、1バイト長くなります。

(.*=|^=.*)1.*
<

ケース3、またはケース1なしのケース4を確認します。

.*1.*=.*
>

1この時点で左の文字列にまだaが含まれている場合、それは大きくなります。

\.

それ以外の場合は、残りを削除します .のsを。

FirefoxブラウザコンソールREPL、19バイト

Services.vc.compare

この内部機能が必要な比較を実行すると思います。-1、0、または1を返します。


1
Firefoxのchromeコードを別の回答として投稿することをお勧めします...
tsh

ところで、Firefoxのchromeコードがどのようにバイトをカウントするのかわかりません。Cu.import("resource://gre/modules/Services.jsm");カウントすべきですか?
tsh

1
私は「ブラウザコンソールREPL」を追加した理由...だ@tsh
ニール・


2

C(gcc)  140  134バイト

このコードは負、出力0またはに対して陽性で<=又は>それぞれ。

i;n;p;q;g(char*s){for(i=n=0;*s&&++n&&*s-46;i=i*10+*s++-48);i=i;}f(char*a,char*b){for(p=q=0;*a+*b&&p==q;b+=n)p=g(a),a+=n,q=g(b);a=p-q;}

オンラインでお試しください!

編集:

  • ceilingcatのおかげで6バイト節約されました!

課題の状態:「3つの定数を個別に使用する」。コードは定数を返しません。
オリヴィエグレゴワール

1
@Olivier「3つの定数を個別に使用できる」と述べています。または「正の数/ゼロ/負の数を使用します。ゼロは等しいことを意味します。」
アンニョ

私の悪い!正解です。
オリビエグレゴワール


1

JavaScript(Node.js)105 88 80バイト

@redundancyから-17バイト。うわー!

-8バイトでMath.signを削除。ありがとう@tsh

負、ゼロまたは正の値を返します

f=(a,b,r=/(\d*).?(.*)/)=>a+b&&+((a=r.exec(a))[1]-(b=r.exec(b))[1]||f(a[2],b[2]))

オンラインでお試しください!


1
exec文字列の分割に使用する88バイト。オンラインでお試しください!
冗長性

@redundancyくそー、ありがとう!それはかなりクールなトリック
ルイスフェリペデジェススムニョス

たぶん、正/ゼロ/負の値に切り替えることで、Math.signを削除していくつかのバイトを節約したいかもしれません。そして、おそらく正のサインが必要です。
tsh

1

Japt16 11バイト

@Shaggyから-5バイト

出力:

  • 負の数 <
  • nullまたは0=
  • の正数 >

N®q.Ãy_r-Ãf

オンラインでお試しください!


、この仕事は?
シャギー

@Shaggyうん、それに短縮することができたバイト10、負、ヌルまたは0をoutputingについて陽性< = >それぞれが、入力アレイとすることができるかどうかは知らない
ルイス・フェリペデイエスムニョス

0

クリーン116 111バイト

import StdEnv,Text
?s=map toInt(split"."s)
$a b= @(?a)(?b)
@[h:t][u:v]|h==u= @t v=h-u
@l[]=sum l
@[]l= ~(sum l)

オンラインでお試しください!

最初の引数が2番目の引数より小さい場合は負の数を出力し、同等の場合はゼロを出力し、2番目の引数が2つより大きい場合は正の数を出力します。


0

スイフト4 4、155バイト

ヘッダー(カウントされません:コードは非再帰的です):

let f:(String,String)->Bool? = 

コード

{let x:(String)->[Int]={$0.split{$0=="."}.map{Int($0)!}.reversed().drop{$0==0}.reversed()},a=x($0),b=x($1)
return a==b ?nil:a.lexicographicallyPrecedes(b)}

オンラインでお試しください!

説明

  • 末尾の.0をトリミングします。
  • コンポーネントを数値的に比較します。

返される定数

  • nil for =
  • <に対して真
  • >の場合はfalse

0

JavaScript 64バイト

a=>b=>(e=i=>(g=v=>v.split`.`[i]||0)(a)-g(b)||!a[i]-1&&e(i+1))(0)

オンラインでお試しください!

コメント付き:

a=>b=>(                            // Main function takes arguments like ("1.2.42")("1.2.41")
    e=i=>                          // e(i) compares the ith number, returns >0, <0 or =0.
        (   g=v=>v.split`.`[i]||0  // g() returns the ith string or 0
        )(a)                       // call g(a)
        -g(b)                      // subtracting g(b) from g(a) casts strings to integer
        ||                         // If they are not equal return result now
        !a[i]-1 &&                 // recursion limited to a.length, always sufficient
        e(i+1)                     // next i
    )(0)                           // Start with i = 0


0

バーレスク-17バイト

wd{'.;;)ri}m[^pcm


blsq ) "2018.08.1 2018.08"wd{'.;;)ri}m[^pcm
1
blsq ) "0.0.1 0.1"wd{'.;;)ri}m[^pcm
-1
blsq ) "1.1.56789 1.2.0"wd{'.;;)ri}m[^pcm
-1

'> <='に出力する場合は、を追加し?i"<=>"j!!Qます。


0

Powershell、88バイト

0等しい、positive integerより大きい、またはnegative integerより小さいを返します。

param($a,$b)+(($x=$a-split'\.')+($y=$b-split'\.')|%{$x[+$i]-$y[$i++]}|?{$_}|Select -f 1)

ゴルフの少ないテストスクリプト:

$f = {

param($a,$b)
$x=$a-split'\.'
$y=$b-split'\.'
$z=$x+$y|%{
    $x[+$i]-$y[$i++]
}|?{$_}|Select -first 1
+$z             # convert $null to 0

}

@(
    ,("2"         ,"1"         , 1)
    ,("1.0.0"     ,"1"         , 0)
    ,("1.0"       ,"1.0.0"     , 0)
    ,("1.2.42"    ,"1.2.41"    , 1)
    ,("1.1.56789" ,"1.2.0"     ,-1)
    ,("1.10"      ,"1.2"       , 1)
    ,("1.20"      ,"1.150"     ,-1)
    ,("18.04"     ,"18.4"      , 0)
    ,("7.010"     ,"7.8"       , 1)
    ,("1.0.0.1.0" ,"1.00.00.2" ,-1)
    ,("00.00.01"  ,"0.0.0.1"   , 1)
    ,("0.0.1"     ,"0.1"       ,-1)
    ,("42.0"      ,"4.2.0"     , 1)
    ,("999.999"   ,"999.999.1" ,-1)
    ,("2018.08.1" ,"2018.08"   , 1)
) | % {
    $v1,$v2,$expected = $_
    $result = &$f $v1 $v2
    "$([Math]::Sign($result)-eq$expected): $result"
}

出力:

True: 1
True: 0
True: 0
True: 1
True: -1
True: 8
True: -130
True: 0
True: 2
True: -1
True: 1
True: -1
True: 38
True: -1
True: 1

0

Dart277 231バイト

F(s,{t}){t=s.split('.').map(int.parse).toList();while(t.last<1)t.removeLast();return t;}f(a,b,{d,e,f,g,h,i=0}){d=F(b);e=F(a);g=d.length;h=e.length;f=h>g?g:h;for(;i<f;i++)if(e[i]!=d[i])return e[i]>d[i]?1:-1;return h>g?1:(h<g?-1:0);}

オンラインでお試しください!

  • -44バイト(変数を使用して長さを格納し、ループ内で3進数を使用)
  • -括弧を削除して-2バイト

0

Swift 4 + Foundation160バイト(142 + 18)、155バイト(142 + 13)

インポート(13バイト、含む ;コードからの分離):

これによりFoundationがインポートされますが、は5バイトより短くなりimport Foundationます。

import UIKit;

ヘッダー(カウントされません:コードは非再帰的です):

let f:(String,String)->ComparisonResult =

コード(142バイト):

{var x={($0 as String).split{$0=="."}.count},a=$0,b=$1
while x(a)<x(b){a+=".0"}
while x(b)<x(a){b+=".0"}
return a.compare(b,options:.numeric)}

オンラインでお試しください!

説明

  1. 同じ数のコンポーネントに対して、末尾に.0を追加します。
  2. コンポーネントを数値的に比較します。

返される定数

  • ComparisonResult.orderedSame for =
  • ComparisonResult.orderedAscending for <
  • ComparisonResult.orderedDescending for>

importステートメントを数えるかどうかわからないので、必要のない別の回答を投稿しましFoundation。142バイト(インポートをカウントしない)と160バイト(インポートをカウントする)の間のバイトカウントです。
クール

0

Zsh、54バイト

eval {autoload,}' is-at-least $'{1\ $2,2\ $1}';<<<$?;'

オンラインでお試しください! テストスイートをお試しください!

これevalは、次の8つのステートメントに当てはまります。

autoload is-at-least $1 $2     # loads the "is-at-least" function
<<<$?                          # success, prints 0
autoload is-at-least $2 $1     # redundant
<<<$?                          # success, prints 0
is-at-least $1 $2              # exits 1 if $1 < $2
<<<$?
is-at-least $2 $1              # exits 1 if $2 < $1
<<<$?

したがって、3つの一意の値は次のとおりです。

 cmp |  value
-----+------------------------------------------
  =  |  0<newline>0<newline>0<newline>0<newline>
  <  |  0<newline>0<newline>1<newline>0<newline>
  >  |  0<newline>0<newline>0<newline>1<newline>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.