Преобразование ISBN-13 в ISBN-10

21

Вступление

В этой задаче ваша задача состоит в том, чтобы сгенерировать код ISBN-10 для книг с учетом кода ISBN-13, предполагая, что такой код существует. Такой код ISBN-13 состоит из нескольких частей, разделенных -:

978-GG-PPPP-TTT-C

Буквы G(группа), P(издатель), T(заголовок) и C(контрольная сумма) обозначают одну цифру. Для этой задачи группировка и вычисление C(см. Эту задачу ) не интересны, и мы упустим все дефисы, чтобы упростить эту задачу.

Номер ISBN-10 имеет очень похожую раскладку:

GG-PPPP-TTT-c

Буквы G, Pи Tтакие же , как для 13 цифр ISBN, однако cотличаются (и вычисляются с использованием другого алгоритма). Цифра cвыбирается таким образом, чтобы выполнялась следующая эквивалентность (цифры по порядку):

10*G + 9*G + 8*P + … + 3*T + 2*T + 1*c = 0 (mod 11)

пример

Рассмотрим номер ISBN 9780345391803: Для того, чтобы получить соответствующий ему ISBN-10 код , который мы просто уронить ведущим 978и контрольная сумма 3приносит 034539180.

Далее нам нужно вычислить новую контрольную сумму:

10*0 + 9*3 + 8*4 + 7*5 + 6*3 + 5*9 + 4*1 + 3*8 + 2*0 = 185

Следующее число делится на 11is 187, поэтому новая контрольная сумма 2и, следовательно, результирующий код ISBN-10 0345391802.

правила

  • Ваш ввод всегда будет иметь соответствующий номер ISBN-10 (т. Е. Он ровно 13 цифр и начинается с 978)
  • Входные данные не обязательно должны быть действительными ISBN-13 (например, 9780000000002)
  • Вы гарантировано, что полученный ISBN не закончится X
  • Вы можете принимать ввод как целое число или строку (с дефисами или без них), однако предварительно вычисленный список цифр не допускается.
  • Ваш вывод должен быть действительным номером ISBN-10 (с дефисами или без них)
  • Ваш вывод может быть целым числом или строкой (опять же нет списков цифр)

Testcases

9780000000002 -> 0000000000
9780201882957 -> 0201882957
9781420951301 -> 1420951300
9780452284234 -> 0452284236
9781292101767 -> 1292101768
9780345391803 -> 0345391802

Обратите внимание на ведущие нули!

ბიმო
источник
5
Это никак не влияет на решения, но просто ради того, чтобы быть тем парнем, ваше описание того, как разделены части ISBN (-10 или -13), неверно. Элемент группы регистрации имеет переменную длину, и количество цифр для последующих частей может варьироваться между и внутри групп регистрации. Например, в обоих 0-684-84328-5и 99921-58-10-7, первая часть ( 0и , 99921соответственно) является регистрация группы, вторая часть является издателем, и так далее.
Иордания
5
Образец 10/10 ISBN
Якоб

Ответы:

10

Retina ,  44  39 28 байт

>,L3,-2`.+
.
$.>`**
_{11}

_

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

объяснение

Время показать некоторые новые функции Retina. :)

>,L3,-2`.+

Мы сопоставляем весь ввод с .+, возвращаем это совпадение L, но выбираем только символы от 3 (начиная с нуля) до -2 (предпоследний) включительно. Мы также печатаем результат без завершающего перевода строки ( >).

Теперь вычитать вещи в Retina немного раздражает. Но, к счастью, мы работаем по модулю 11, поэтому мы можем просто инвертировать коэффициенты линейной комбинации (мод 11) и сложить все. Другими словами, если ограничение:

10*G + 9*G + 8*P + … + 3*T + 2*T + 1*c = 0 (mod 11)

тогда мы получим:

c = 1*G + 2*G + 3*P + … + 8*T + 9*T (mod 11)

Это многое упрощает здесь:

.
$.>`**

Мы заменяем каждого персонажа этой вещью внизу. *является оператором повторения Retina. Он ассоциативен справа и имеет неявные операнды $&слева и _справа, поэтому замена на самом деле коротка $.>`*$&*_. $&*_создает строку с подчеркиванием d , где d - это цифра, которую мы в настоящее время заменяем. Затем $.>`длина строки до совпадения. 1 Следовательно, все выражение приводит к унарному представлению n- го члена нашей линейной комбинации.

_{11}

Выполнение фактического по модулю в унарном тривиально: мы просто отбрасываем все полные наборы из 11 подчеркиваний.

_

Наконец, мы подсчитываем, сколько осталось подчеркиваний, и печатаем результат, который завершает ISBN-10.


1 Как определить $.>`длину строки до совпадения? Вы можете быть знакомы с $`подстановками регулярных выражений, которые дают вам строку до (но исключая) совпадения. Вставив a >, мы можем сместить контекст $`с в разделитель между текущим соответствием и следующим (то есть пустой строкой между текущей цифрой и следующей). Этот разделитель $`будет включать текущее совпадение. Так что $>`это более короткий способ написать $`$&. Наконец, для всех $xподстановочных элементов Retina позволяет вставлять .после, $чтобы получить его длину.

Мартин Эндер
источник
Что это за магия по модулю 11 ?! Это сэкономит мне 4 байта ... но я не понимаю!
Стритстер
1
@streetster В основном, -2 ≡ 9 (mod 11)(потому что добавление или вычитание 11 из числа не меняет его «значение» в моде класса конгруэнции 11). А сложение и умножение учитывают классы конгруэнтности, поэтому вы можете заменить любое значение в линейной комбинации эквивалентным значением в текущем модуле. Причина, по которой я говорю об отрицательных числах, заключается в том, что я просто перестроил уравнение, чтобы иметь cодну сторону, а все остальные термины (как отрицательные) - с другой.
Мартин Эндер
Я думаю, я понял это сейчас. Таким образом, вы переходите, cчтобы стать, -c = ...и вместо того, чтобы умножать на 10 9 8...вас, вычитаете 11из каждого, чтобы получить, -1 -2 -3...а затем умножаете все на -1, чтобы получить c.
Стритстер
Не могли бы вы объяснить, почему последний этап заменяет только заключительные подчеркивания? Я потратил некоторое время, пытаясь выяснить, что является причиной этого, но я не могу воспроизвести это. Кстати, это обновление выглядит потрясающе, отличная работа!
FryAmTheEggman
1
@FryAmTheEggman Спасибо :) В этот момент строка содержит только подчеркивания. Мы уже напечатали первые девять цифр на первом этапе.
Мартин Эндер
6

05AB1E , 17 15 13 12 байт

¦¦¦¨DSƶO11%«

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

объяснение

¦¦¦            # remove the first 3 characters
   ¨           # remove the last character
    D          # duplicate
     S         # split to list of digits
      ƶ        # multiply each by its 1-based index
       O       # sum
        11%    # mod by 11
           «   # concatenate
Emigna
источник
5

PowerShell , 96 84 байта

$y=-(([char[]]($x="$args"-replace'^978|.$')|%{--$a*[int]"$_"})-join'+'|iex)%11;$x+$y

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

Принимает ввод "$args", выполняет регулярное выражение, -replaceчтобы получить только соответствующую часть, сохраняет ее в $xвиде строки. Затем мы приводим это как charмассив и перебираем каждую букву. Внутри цикла мы предварительно уменьшаем $a(что по умолчанию 0) и умножаем в соответствии с вычислением контрольной суммы. Обратите внимание на приведение к int, иначе это будет использовать значения ASCII.

Затем мы получим -joinэти числа вместе +и передадим их iex( Invoke-Expressionи аналогично eval). Мы берем это %11и храним эту контрольную сумму в $y. Наконец, мы объединяем строки $x + $yи оставляем их на конвейере. Вывод неявный.

Сохранено 12 байтов благодаря Emigna.

AdmBorkBork
источник
Я действительно не знаю , PowerShell, но я думаю , что- то вроде этого может работать на 84
Emigna
@ Emigna Да, конечно. Модуль арифметики и мой мозг не играют хорошо.
AdmBorkBork
5

Октава , 46 41 39 37 байт

@(a)[c=a(4:12) 48+mod(7+c*(1:9)',11)]

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

Код принимает входные данные в виде строки и возвращает строку.

Код разбивается следующим образом:

@(a) создает анонимную функцию.

С помощью [c=a(4:12) ... ]мы извлекаем символы, которые образуют основной код, сохраняя копию cдля последующего использования и добавляя еще одну копию в окончательную строку вывода.

На основе @ умный способ MartinEnter в замещающей 10:-1:2в 1:10, мы можем легко генерировать этот диапазон и перенести его , чтобы получить вектор - столбец. c*(1:10)'выполняет умножение массива вектора строки и вектора cстолбца диапазона. Это эквивалентно поэлементному умножению, а затем суммированию.

Контрольной суммой обычно является mod(11-sum,11)вычисление числа, необходимого для того, чтобы сумма была кратна 11. Однако, поскольку это cбыла символьная строка, сумма на самом деле будет больше, чем должна быть на 2592 (48 * 54), потому что мы умножаем на числа это было на 48 больше, чем фактическое значение.

Когда мы выполняем по модулю, он автоматически избавится от всего, кроме 7, от 2592. Таким образом, и с учетом отрицания диапазона, фактический расчет становится 48+mod(7+sum,11). Мы добавляем 48 к результату, чтобы преобразовать обратно в символ ASCII.

Символ контрольной суммы добавляется в конец результата и возвращается значение.

Том Карпентер
источник
5

Желе , 12 байт

ṫ4ṖȮV€xJS%11

Это полная программа, которая использует строки для ввода / вывода.

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

Как это устроено

ṫ4ṖȮV€xJS%11  Main link. Argument: s (string of length 13)

ṫ4            Tail 4; discard the first three characters.
  Ṗ           Pop; discard the last characters.
   Ȯ          Output; print the result to STDOUT and return it.
    V€        Eval each; turn digit characters into digits.
       J      Indices; yield [1, ..., 13].
      x       Repeat the first digit once, the second digit twice, etc.
        S%11  Take the sum, modulo 11.
              (implicit) Print the checksum to STDOUT.
Деннис
источник
4

JavaScript (ES6), 59 56 байт

s=>(s=s.slice(3,-1))+[...s].reduce(n=>n+s[i++]*i,i=0)%11

-3 байта благодаря предложению @ Shaggy .

darrylyeo
источник
57 байт ?
Лохматый
1
Или, может быть, даже 56 байтов .
Лохматый
Так почему бы не ввести как массив цифр? 54 байта
tsh
3

Pyth , 16 байт

%s.e*ksbpP>Q3hT

Попробуй это здесь!

Pyth , 17 байт

%s*VsMKpP>Q3SlK11

Попробуй это здесь!

объяснение

%s.e*hksbpP>Q3hT || Full program. Uses string for input and output.

            Q    || The input.
           > 3   || With elements at indexes smaller than 3 trimmed.
          P      || Pop (remove the last item).
         p       || Print the result without a linefeed, but also return it.
  .e             || Enumerated map. For each (index, value), assign two variables (k, b).
       sb        || b converted to an integer.
    *hk          || And multiplied by k + 1.
 s               || Summation.
%                || Modulo by:
               T || The literal 10.
              h  || Incremented by 1.
Мистер Xcoder
источник
3

Japt , 16 15 байт

Пришел с этим в пабе прошлой ночью и забыл все об этом.

s3J
U+¬x_*°TÃuB

Попытайся

мохнатый
источник
Думаю, что вы можете сохранить байт с s3JиU+¬x_*°TÃuB
ETHproductions
Weird; мог бы поклясться, что попробовал. Спасибо, @ETHproductions.
лохматый
Подожди, нет, я забыл ... UО!
лохматый
3

Гексагония , 77 61 байт

,,,,'~'11=\.A&.=\./';"-'"{4.8}}\'.A.>.,<\'+'%!@}/=+'+{./&{{&/

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


Цветное:


Вот увеличенная версия. Есть некоторые пересечения путей, но, поскольку все эти ячейки .(без операции в Hexagony), вам не нужно беспокоиться о них:

(Я тоже пытался сохранить старые зеркала, но иногда мне нужно что-то менять)

Выполненная линейная команда:

,,,,'48}}
,
while memory > 0:
    ';"-'"{+'+{=A&=''A
    if memory < 0:
        undefined behavior
    &{{&}
    ,
'"''+~'11='%!@

Пояснение: Вместо того чтобы вести счетчик и делать умножение на каждую цифру, эта программа:

  • сохранить переменную "частичная сумма" и переменную "общая сумма" ( pи t)
  • для каждой прочитанной цифры: добавьте ее к частичной сумме и добавьте частичную сумму к общей сумме.
  • печать (-p-t)%11, где %всегда возвращаются положительные результаты.
user202729
источник
3

K (ок) , 29 25 24 23 байта

Решение:

x,$11!7+/(1+!9)*x:-1_3_

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

Примеры:

x,$11!7+/(1+!9)*x:-1_3_"9780000000002"
"0000000000"
x,$11!7+/(1+!9)*x:-1_3_"9780345391803"
"0345391802"
x,$11!7+/(1+!9)*x:-1_3_"9781292101767"
"1292101768"
x,$11!7+/(1+!9)*x:-1_3_"9780452284234"
"0452284236"

Объяснение:

Оценка выполняется справа налево.

Два трюка взяты из других решений:

  • умножить на 1 2 3 ... вместо 10 9 8 ...
  • умножьте значения ASCII, а затем добавьте 7 к сумме, чтобы сбалансировать

Сломать:

x,$11!7+/(1+!9)*x:-1_3_ / the solution
                     3_ / drop three items from the start
                  -1_   / drop one item from the end
                x:      / save this as variable x
               *        / multiply by
         (    )         / all this together
            !9          / til, !9 => 0 1 2 3 4 5 6 7 8
          1+            / add 1 => 1 2 3 4 5 6 7 8 9
      7+/               / sum (+) over (/), start from 7
   11!                  / mod by 11
  $                     / convert back to a string
x,                      / join with x

Заметки:

  • -4 байта благодаря магии Мартина Эндерса " просто инвертировать коэффициенты ".
  • -1 байт благодаря Tom Carpenter за то, что он убрал необходимость преобразования в целые числа (добавив 7к сумме)
  • -1 байт запускает аккумулятор на 7
streetster
источник
3

C (gcc), 96 95 87 86 85 байт

(-1 благодаря потолочной кошке)

*f(s,r,c,d)char*s,*r;{for(d=13;--d;s+=*++s<48)r=d>8?c=3,s:r,c-=~d**s;*s=58-c%11;s=r;}

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

Вызывается как f(s), где sуказатель на первый элемент изменяемого массива символов. Изменяет входной массив, возвращает указатель на входной массив.

HVD
источник
2

ECMAScript 6 , 86 67 байт

a=>(c=a.substr(3,9))+([...c].map(v=>g+=--i*v,e=i=g=11)?(e-g%e)%e:0)

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


Спасибо за комментарий Arnauld в , перешли от reduceк mapи избавились от returnключевого слова.

Кос
источник
3
Добро пожаловать в PPCG! Ответы должны быть либо полными программами, либо вызываемыми функциями (хотя они могут быть неназванными функциями), а не просто фрагментами. Я считаю, что самым коротким вариантом в JavaScript обычно является безымянная лямбда.
Мартин Эндер
@MartinEnder спасибо, я отредактировал свой ответ
Кос
3
Добро пожаловать на борт! Некоторые советы: Инициализацию переменная обычно можно поместить в качестве дополнительных параметров map(), и reduce()т.д. С некоторым дополнительным переписыванием, это часто можно избавиться {}и return. Кроме того, в данном конкретном случае, map()вероятно, короче reduce(). ( Вот 65-байтовая версия.)
Арно
Я уверен, что в f=этом нет необходимости. Кроме того, вы можете инициализировать cпри a=>{i=10;s=[...c=a.substr(3,9)].reduce((g,v)=>+g+(i--)*v,0)%11;return c+=s?11-s:0}
спреде
2

Сетчатка 0.8.2 , 72 51 байт

...(.*).
$1¶$1
r`.\G
$&$'
r`.\G
$*
1{11}

¶(1*)
$.1

Попробуйте онлайн! Потому что я еще не выучил Retina 1.0. Объяснение:

...(.*).
$1¶$1

Удалите ненужные символы и сделайте вторую копию соответствующих цифр.

r`.\G
$&$'

Суффикс каждой цифры во втором экземпляре с суффиксом. Это эффективно повторяет каждую цифру в суффиксе по ее позиции.

r`.\G
$*

Преобразуйте цифры во второй копии в одинарные, таким образом, сложив их вместе.

1{11}

Уменьшите по модулю 11. (В первой копии всего 9 цифр, поэтому это никак не повлияет).

¶(1*)
$.1

Преобразуйте результат обратно в десятичную и снова удалите новую строку.

Нил
источник
2

APL (Dyalog Unicode) , 26 24 байта

∊⍕¨(⊢,11|⊢+.×⍳∘≢)3↓¯1↓⍎¨

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

Функция молчаливого префикса. Принимает ввод в виде строки.

2 байта сохранены благодаря @ngn.

Как?

∊⍕¨(⊢,11|⊢+.×⍳∘≢)3↓¯1↓⍎¨     Main function.
                       ⍎¨     Execute each; turns the string into a vector of digits.
                 3↓¯1        Drop (↓) the last 1) and the first 3 digits.
   (           ≢)             Tally; returns the number of digits in the vector.
             ⍳∘                Then (∘) index (⍳) from 1
            ×                 Multiply the resulting vector [1..9]
         ⊢+.                  Dot product with sum with the original vector;
                              This will multiply both vectors, and sum the resulting vector.
      11|                     Mod 11
     ,                        Concatenate
                             With the original vector
 ⍕¨                           Format each; returns a vector of digits as strings.
                             Flatten to get rid of the spaces.
Ж. Салле
источник
1

Котлин , 83 байта

i.drop(3).dropLast(1).let{it+(11-(it.mapIndexed{i,c->(10-i)*(c-'0')}.sum()%11))%11}

украшенный

i.drop(3).dropLast(1).let {
    it + (11 - (it.mapIndexed { i, c -> (10 - i) * (c - '0') }.sum() % 11)) % 11
}

Тестовое задание

data class Test(val input: String, val output: String)

fun f(i: String) =

i.drop(3).dropLast(1).let{it+(11-(it.mapIndexed{i,c->(10-i)*(c-'0')}.sum()%11))%11}

val tests = listOf(
        Test("9780000000002", "0000000000"),
        Test("9780201882957", "0201882957"),
        Test("9781420951301", "1420951300"),
        Test("9780452284234", "0452284236"),
        Test("9781292101767", "1292101768"),
        Test("9780345391803", "0345391802")
)

fun main(args: Array<String>) {
    for (c in tests) {
        val answer = f(c.input)
        val good = answer == c.output
        println("$good ${c.input} -> ${c.output} | $answer")
    }
}

TIO

TryItOnline

jrtapsell
источник
1

PHP, 64 байта

К сожалению, в PHP так (-$c)%11же, как -($c%11); поэтому я должен получить разницу как минимум до максимально возможной суммы (55 * 9 = 495 = 45 * 11), а не просто использовать -$c%11.

for($f=11;--$f>1;print$d)$c+=$f*$d=$argn[13-$f];echo(495-$c)%11;

или

for($c=45*$f=11;--$f>1;print$d)$c-=$f*$d=$argn[13-$f];echo$c%11;

Запустите как трубу с -nRили попробуйте их онлайн .

Titus
источник
0

Java 10, 110 байт

l->{var s=l+"";int c=0,i=3;for(;i<12;)c+=(13-i)*(s.charAt(i++)-48);return(l-(long)978e10)/10*10+(11-c%11)%11;}

Принимает ввод и вывод в виде longцелого числа. Попробуйте это онлайн здесь .

Безголовая версия:

l -> { // lambda taking a long as argument
    var s = l + ""; // convert the input to a String
    int c = 0, // the check digit
    i = 3; // variable for iterating over the digits
    for(; i < 12 ;) // go from the first digit past 978 to the one before the check digit
        c += (13 - i) * (s.charAt(i++) - 48); // calculate the check sum
    return (l - (long) 978e10) // remove the leading 978
           /10 *10 // remove the original check digit
           + (11 - c % 11) % 11; // add the new check digit
}
OOBalance
источник