Сравнить номера версий


26

Когда мы публикуем какое-то программное обеспечение, мы присваиваем ему номер версии. И пользователи могут захотеть обновить программное обеспечение до последней версии. Итак, пришло время узнать, какая версия должна быть новее.

вход

Введите два номера версии в виде строк.

В контексте этой задачи мы поддерживаем только номера версий, которые представляют собой несколько цифр, соединенных точками.

  • Номер версии - это строка, которая может содержать только цифры ( 0~ 9) и точки ( .).
  • Точки не будут первым / последним символом номера версии.
  • Между точками должно быть несколько цифр. Никакие две точки не могут появляться непрерывно.
  • Все числа в номере версии будут меньше чем 2 16 .

Выход

Сравните введенные номера версий и выведите, будет ли первый вариант больше / равен / меньше второго. Вам разрешено выбрать одну из следующих презентаций:

  • Используйте положительное число / ноль / отрицательное число, в то время как ноль означает равный;
  • Используйте три постоянных различных значения;

Сравнение

Вы не обязаны реализовывать алгоритм, описанный в этом разделе. Ваша заявка действительна до тех пор, пока это приводит к тому же результату с этим алгоритмом.

  • Номера версий - это некоторые десятичные числа, соединенные точками. Сначала мы разбиваем два номера версий на массивы чисел;
  • Заполнение концов массивов нулями, чтобы они имели одинаковую длину;
  • Сравните с первого элемента до последнего:
    • Если два элемента массива отличаются, большее число означает больший номер версии
    • Если они совпадают, продолжайте сравнивать следующие элементы;
    • Если все элементы в массиве равны, две версии равны.

Testcases

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, но в нем не поддерживается один символ :(
Брайан Дж

@BrianJ и добавление '.0' стоит многим символам? :)
RobAu

Ну, на самом деле он ожидает 2, 3 или 4 порции. Так что это не сработало в тестовом примере 1.0.0.1.0 (хотя я и попробовал вашу идею изначально :))
Брайан Дж

Я думаю, что в Windows есть встроенная программа, которая будет делать это: StrCmpLogicalW
bace1000

Ответы:



6

05AB1E (наследие) , 15 14 13 байтов

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

Выходы -1 [] 1для < = >соответственно.

-1 байт благодаря @Emigna .

Попробуйте онлайн или проверьте все контрольные примеры .

Объяснение:

'.¡              # 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

@ Emigna Ну конечно .. Спасибо.
Кевин Круйссен

5

R , 32 байта

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

Попробуйте онлайн!

Использование встроенного R

Выходы 1 2, 1.5 1.5, 2 1для меньше, равно, больше.


Лучше всего пока без встроенных:

R , 151 142 125 107 байт

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)

Выходы -1, NULL, 1для меньше, равно, больше.


Оригинальная концепция, игра в гольф 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]

Попробуйте онлайн!

Теперь у вас есть список двух равных по длине векторов целых чисел. Рассчитайте попарные разности, используя Reduceи выведите первый ненулевой элемент, используя хитрую маленькую w[!!w][1]форму в конце.

Выходы -1, NA, 1для меньше, равно, больше.


Впечатляет! Быстрый гольф: дополнительная
новая строка

уменьшить количество именованных переменных ... . Я чувствую, что есть способ сделать это, используя матрицу вместо списков, но я еще не нашел, как это сделать.
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](или 106, если вы хотите вернуть -1, NA, 1 не (отрицательный), NA, (положительный).
mnel

1
@mnel 100-байтовое решение требует небольшой работы. Это терпит неудачу в последних двух тестовых случаях. 0Заполнение должно быть, а не (имплицитно) NA. Я сделал ответ на вики сообщества, так что тот, кто сможет это исправить, может просто добавить его.
НГМЫ

1
@digEmAll сыграл 4 байта, сначала вычислив знак, а затем сделай Find(c,x). Я думаю, что это новый трюк.
JayCe

4

APL (Dyalog Unicode) , 18 17 байт

1 байт сохранен благодаря @ Adám за использование ⍤1вместо ∘↑(...)¨и путем изменения формата ввода с вложенного массива на матрицу

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

Попробуйте онлайн!

Принимает входные данные как матрицу символов в качестве правильного аргумента, где каждая строка версии находится в отдельной строке. Выходы ¯1 1, 0 0, 1 ¯1для <, =, >соответственно.

(⍎¨∊∘⎕D⊆⊢)⍤1 на каждом ряду

  • ∊∘⎕D⊆⊢ сгруппировать все вхождения цифр, то есть разбить на .

  • ⍎¨ и преобразовать каждое из этих вхождений в число

преобразовать в матрицу, где первый вход находится в верхней строке, а второй - в нижней, добавляя, 0где необходимо, s

(⍋-⍒) а также

  • - вычитать
    • индексы в строках, которые будут сортировать их в порядке убывания
    • так же, как верх, но по возрастанию

4

Perl 6 , 63 47 22 байта

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

Попробуйте онлайн!

Оказывается, что Perl 6 имеет тип версии, который в значительной степени соответствует описанию. Это блок анонимного кода, который принимает список из двух строк версии и возвращает либо More, Sameлибо 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],@_}

Попробуйте онлайн!

Блок анонимного кода, который принимает две строки и возвращает значение, Moreесли второе больше, 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

Брахилог , 49 40 байт

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

... Это все еще довольно впечатляюще долго.

Ожидается список из двух строк. Использует 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]). Повторить на втором подсписке. Обратите внимание, что предикат zip zциклически перебирает короткие списки, так что zip с [0,0]равносильно ziping с [0], поэтому предыдущий шаг объединяется 0с 0дополнительными значениями.

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 байт

Сохранено 5 байт благодаря @redundancy

Принимает вход как (a)(b). Возвращает для равных , положительное целое число больше или отрицательное целое меньше .0

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

Попробуйте онлайн!


Ницца. Если я правильно понял, вы можете сохранить байт, заменяя replaceс fill. Операнды для -меняются местами, поскольку теперь оба должны быть приведены к числу. Попробуйте онлайн!
резервирование

@ redundancy Хорошая идея! (Хотя я не уверен, что моя реализация - именно то, что вы имели в виду.)
Арно

Я предположил , ваше намерение было приложить достаточно значение сжимаемого до 0 такое , что отображения над подстроками в aконце концов циклов с помощью этих значений 0 , если bсодержит больше сегментов , чем числа a. Бывает так, что самый короткий способ bубедиться, что это так, - это разделить строку длиной «». используя существующее разделение, примененное к a.
резервирование

3

Java (JDK 10) , 201 96 89 байт

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

Попробуйте онлайн!

Возвращает отрицательное число, если первая версия меньше, чем вторая, положительное, если первая версия больше, чем вторая, и 0если они равны.

Да, это какая-то тяжелая работа, чтобы "просто" вызвать встроенный!

кредиты


1
Я пытался, но я могу удалить только три байта .. 228 байтов
Кевин Круйссен

1
Нашел что-то большее: 217 байтов
Кевин Круйссен

1
Вероятно, это так. Уже пробовал, try-finallyтак что проверка if может быть упрощена; попытался вернуться в цикл 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

Сетчатка 0.8.2 , 54 байта

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

Попробуйте онлайн! Ссылка включает в себя тестовые случаи. Использует значение разделителя в качестве выходного равенства, поэтому для удобства заголовок преобразует входной разделитель, =но это может быть что-то, чего нет [.\d]. Объяснение:

\d+
$*

Преобразовать в одинарный.

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

Повторно удаляйте первый символ с каждой стороны, пока они не будут отличаться или не закончится одна сторона. Это намного быстрее, чем пытаться сопоставить префиксы, хотя, возможно, не в гольф. На этом этапе строки находятся в одной из нескольких форм, которые должны быть декодированы до результата сравнения.

  1. Если ни одна из строк не содержит, 1то результат=
  2. Если левая строка начинается с, 1то результат>
  3. Если правая строка начинается с, 1то результат<
  4. Если левая строка пуста, то результат <
  5. На данный момент правая строка пуста, поэтому результат >

Другой способ думать об этом состоит в том, что если одна строка содержит a, 1а другая не начинается с a, 1то эта строка больше, однако это оказывается на байт длиннее.

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

Проверьте случай 3 или случай 4 без случая 1.

.*1.*=.*
>

Если левая строка все еще содержит 1в этой точке, то она больше.

\.

В противном случае удалите все оставшиеся над .s.

Браузерная консоль Firefox REPL, 19 байт

Services.vc.compare

Я считаю, что эта внутренняя функция выполняет необходимое сравнение. Возвращает -1, 0 или 1.


1
Я бы посоветовал вам опубликовать хром-код Firefox в качестве другого ответа ...
tsh

Кстати, я не уверен, как хром-код Firefox подсчитывает свои байты. Стоит Cu.import("resource://gre/modules/Services.jsm");ли считать?
Tsh

1
@tsh Вот почему я добавил "Browser Console REPL" ...
Нил

2

PHP , 38 байт

<?=version_compare($argv[1],$argv[2]);

Выходы -1 → < | 0 → = | 1 → >

Попробуйте онлайн!


Я думаю, что ваше представление может быть просто самой функцией
Джо Кинг,

1
Это возвращает неправильный результат для любой пары входов, которые отличаются только 1.0.01
конечными

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;}

Попробуйте онлайн!

Редактирование:

  • Сэкономлено 6 байт благодаря потолку!

Задача гласит: «Используйте три постоянных различных значения;» Ваш код не возвращает константы.
Оливье Грегуар,

1
@Olivier В нем говорится, что я могу "использовать три постоянных различных значения;" ИЛИ «Используйте положительное число / ноль / отрицательное число, в то время как ноль означает равный;»
Annyo

Виноват! Ты прав.
Оливье Грегуар


1

JavaScript (Node.js) , 105 88 80 байт

-17 байт из @redundancy. Вот Это Да!

-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
88 байтов используется execдля разделения строк. Попробуйте онлайн!
резервирование

@ redundancy Черт, спасибо! это довольно крутой трюк
Луис Фелипе Де Иисус Муньос

Возможно, вы захотите удалить Math.sign, чтобы сохранить несколько байтов, переключившись на положительные / нулевые / отрицательные значения. И, возможно, положительный знак не требуется.
TSH

1

Japt , 16 11 байт

-5 байт от @Shaggy

Выходы:

  • отрицательное число для <
  • ( nullили 0) для=
  • положительное число для >

N®q.Ãy_r-Ãf

Попробуйте онлайн!


Будет ли это работать?
Лохматый

@Shaggy Да, это может быть укоротить до 10 байт outputing отрицательных, нулевого или 0, положительного для < = >соответственно , но я не знаю , если входной сигнал можно рассматривать как массив
Луис Филипе де Хесус Муньос

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)

Попробуйте онлайн!

Выводит отрицательное число, если первый аргумент меньше, чем второй, ноль, если они эквивалентны, и положительное число, если оно больше, чем второй.


0

Swift 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.
  • Мы сравниваем компоненты численно.

Возвращенные константы

  • ноль для =
  • верно для <
  • ложь для>

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

Дротик , 277 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 байта с помощью переменных для хранения длины и использования троичного в цикле
  • -2 байта, сняв скобки

0

Swift 4 + Foundation , 160 байт (142 + 18) , 155 байт (142 + 13)

Импорт (13 байт, в том числе ;для отделения от кода):

Это импортирует основание, но на 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 для>

Я не уверен, если мы посчитаем это importутверждение, поэтому я опубликовал отдельный ответ , который не требует Foundationи с количеством байтов между 142 байтами (не считая импорт) и 160 байтами (считая импорт).
Кер

0

Zsh , 54 байта

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

Попробуйте онлайн! Попробуйте набор тестов!

Это evalотносится к следующим восьми утверждениям:

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
<<<$?

Итак, три уникальных значения:

 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>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.