Перетворення 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

Наступне число, яке ділиться на, 11є 187новою контрольною сумою, 2і, таким чином, отриманий код ISBN-10 0345391802.

Правила

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

Тестові шафи

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

Сітківка ,  44  39 28 байт

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

_

Спробуйте в Інтернеті!

Пояснення

Час показати нові функції Retina. :)

>,L3,-2`.+

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

Тепер віднімання речей у Retina трохи дратує. Але, на щастя, ми працюємо за модулем 11, тому ми можемо просто перевернути коефіцієнти лінійної комбінації (mod 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 дозволяє вставити a .після, $щоб отримати його довжину.


Що це за магія модуля 11 ?! Це врятує мене 4 байти ... але я не отримую!
Стрітер

1
@streetster В основному, -2 ≡ 9 (mod 11)(тому що додавання або віднімання 11 з числа не змінює його "значення" в класі конгруентності mod 11). І додавання і множення поважає класи конгруентності, тому ви можете замінити будь-яке значення в лінійній комбінації на еквівалентне значення за поточним модулем. Причина, про яку я говорю про негативні числа, насправді полягає лише в тому, що я переставив рівняння, яке має cна одній стороні, а всі інші терміни (як негативи) з іншого.
Мартін Ендер

Я думаю, я зараз це зрозумію. Таким чином, ви переходите cдо того, щоб ставати, -c = ...а не множуватись, 10 9 8...віднімаючи 11кожне, щоб отримати, -1 -2 -3...а потім помножуєте все на -1, щоб отримати c.
стрітер

Ви б не хотіли пояснити, чому остаточний етап лише замінює останні підкреслення? Я витратив деякий час, намагаючись з’ясувати, що це спричиняє, але я не можу, здається, це відтворити. До речі, це оновлення виглядає дивовижно, приємна робота!
FryAmTheEggman

1
@FryAmTheEggman Спасибі :) У цей момент рядок містить лише підкреслення. Ми вже надрукували перші дев'ять цифр на першому етапі.
Мартін Ендер


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 байт завдяки Еміньї.


Я дійсно не знаю , 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 в .



1
А може, навіть 56 байт .
Кудлатий

То чому б не ввести як масив цифр? 54 байти
tsh


3

Pyth , 16 байт

%s.e*ksbpP>Q3hT

Спробуйте тут!

Піт , 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.

3

Japt , 16 15 байт

Нещодавно підійшов до цього в паб і забув про це все.

s3J
U+¬x_*°TÃuB

Спробуй це


Подумайте, ви можете зберегти байт за допомогою s3JтаU+¬x_*°TÃuB
ETHproductions

Дивний; міг присягнути, що я спробував це. Дякую, @ETHproductions.
Кудлатий

Зачекайте, ні, я забув U- D'oh!
Кудлатий

3

Шестикутник , 77 61 байт

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

Спробуйте в Інтернеті!


Кольорові:


Ось більша версія. Є кілька перетинів шляху, але тому, що всі ці клітини є. (неоперативні в Гексагонії), вам не потрібно турбуватися про них:

(Я також намагався зберегти старі дзеркала, але іноді мені потрібно щось змінити)

Лінійна команда, що виконується:

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

Пояснення: Замість того, щоб зберігати лічильник і робити множення на кожній цифрі, ця програма:

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

3

К (оК) , 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 байт завдяки Тому Карпентеру за те, що він усунув необхідність перетворення на цілі числа (додавши 7до суми)
  • -1 байт запустити акумулятор на 7

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є вказівник на перший елемент масиву символів, що змінюється. Модифікує вхідний масив, повертає вказівник на вхідний масив.




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}(-4 байти)
Асона Тухід

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")
    }
}

ТІО

TryItOnline



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або спробуйте їх онлайн .


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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.