Обчисліть контрольну цифру ISBN-13


28

Напишіть функцію, яка з урахуванням перших 12 цифр коду ISBN-13 обчислить весь ISBN за допомогою обчислення та додавання відповідної контрольної цифри.

Вхід вашої функції - рядок, що містить перші 12 цифр ISBN. Його вихід - рядок, що містить усі 13 цифр.

Офіційна специфікація

Напишіть функцію, яка при заданому рядку s складається повністю з 12 знаків після коми (та жодних інших символів), повертає рядок t із такими властивостями:

  • t складається з рівно 13 десяткових цифр (і жодних інших символів);
  • s - префікс t ;
  • сума всіх цифр у непарних позиціях у t (тобто перша, третя, п’ята тощо) плюс три рази більша сума всіх цифр у парних позиціях у t (тобто друга, четверта, шоста тощо), є a кратне 10.

Приклад / тестовий випадок

Вхідні дані
978030640615

Вихідні дані
9780306406157

Стан перемоги

Як , найкоротша відповідь виграє.


1
Чи вхідні та вихідні дані повинні містити тире або лише цифри?
sepp2k

1
Оновлено опис, введення та вихід - лише цифри
Кевін Браун

Чи прийнятний також вихід повного ISBN-13?
Містер Лама

6
Зауважте, що питання дійсно повинні бути самостійними, тому було б корисно включити сюди опис алгоритму.
FlipTack

Для мене вище повідомлення є поганим прикладом тесту ... Буде нарешті 10 isbn, і один з них повинен повернути 0 як останню цифру ...
RosLuP

Відповіді:


14

Гольфскрипт - 25 символів

{...+(;2%+{+}*3-~10%`+}:f

Уся версія програми становить лише 19 символів

...+(;2%+{+}*3-~10%

Зверніться сюди для аналізу пізніше. Тим часом перевірте мою стару не натхненну відповідь

Гольфскрипт - 32 символи

Подібно до обчислення числа Луна

{.{2+}%.(;2%{.+}%+{+}*~)10%`+}:f

Аналіз на 978030640615

{...}:f this is how you define the function in golfscript
.       store an extra copy of the input string
        '978030640615' '978030640615'
{2+}%   add 2 to each ascii digit, so '0'=>50, I can get away with this instead
        of {15&}% because we are doing mod 10 math on it later
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55]
.       duplicate that list
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [59 57 58 50 53 50 56 54 50 56 51 55]
(;      trim the first element off
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [57 58 50 53 50 56 54 50 56 51 55]
2%      select every second element
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [57 50 50 54 56 55]
{.+}%   double each element by adding to itself
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [114 100 100 108 112 110]
+       join the two lists together
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55 114 100 100 108 112 110]
{+}*    add up the items in the list
        '978030640615' 1293
~       bitwise not
        '978030640615' -1294
)       add one
        '978030640615' -1293            
10%     mod 10
        '978030640615' 7
`       convert to str
        '978030640615' '7'
+       join the strings
        '9780306406157'

Після запуску коду через інтерпретатора, я думаю, ви можете зберегти деякі символи (у своєму 32-символьному рішенні на основі Луна), позбувшись першого {та останніх трьох символів; }:f. Цікаво, чи можна зробити те ж саме для першого рішення ...
Роб

@MikeDtrick, ці символи - це те, як GS визначає функцію. Версія для 19 чарівників робить те, що ви пропонуєте, але в питанні було задано "функцію"
gnibbler

Добре, дякую за пояснення.
Роб

Вам не потрібно :f(так, я знаю, функції тоді називались зазвичай).
Ерік Аутгольфер

8

Пітон - 44 символи

f=lambda s:s+`-sum(map(int,s+s[1::2]*2))%10`

Пітон - 53 символи

def f(s):d=map(int,s);return s+`-sum(d+d[1::2]*2)%10`

Я думаю, що f ('9780306406159') виводить '97803064061598' замість '9780306406157'
Eelvex

@Eelvex, рядок вводу завжди повинен бути 12 цифр
gnibbler

Ах, як - то '9' прокрався ... До жаль.
Eelvex

7

Haskell - 54 символи

i s=s++show(sum[-read[c]*m|c<-s|m<-cycle[1,3]]`mod`10)

Для цього потрібна підтримка паралельного розуміння списку , яке підтримується GHC (з -XParallelListCompпрапором) та Hugs (з -98прапором).


Вам не потрібно включати цей прапор до рахунку? Крім того, ви можете замінити [1,3]на [9,7]і видалити -що економить байт :)
ბიმო

7

APL (27 символів)

F←{⍵,⍕10|10-(12⍴1 3)+.×⍎¨⍵}

Я використовую Dyalog APL в якості мого перекладача. Ось коротке пояснення, в основному справа наліво (в межах визначення функції, F←{ ... }):

  • ⍎¨⍵: Виконати / оцінити ( ) кожен ( ¨) символ, заданий у правильному аргументі ( ).
  • (12⍴1 3): Переформатуйте ( ) вектор 1 3у вектор- 12елемент (повторюючи, щоб заповнити прогалини).
  • +.×: Візьміть крапковий добуток ( +.×) лівого аргументу ( (12⍴1 3)) та його правого аргументу ( ⍎¨⍵).
  • 10-: Віднімаємо від 10.
  • 10|: Знайдіть залишок після поділу на 10.
  • : Відформатуйте число (тобто, подайте символьне зображення).
  • ⍵,: Додайте ,до обчисленої цифри правильний аргумент.

6

PHP - 86 85 82 символів

function c($i){for($a=$s=0;$a<12;)$s+=$i[$a]*($a++%2?3:1);return$i.(10-$s%10)%10;}

Переформатування та пояснення:

function c($i){                     // function c, $i is the input

    for($a=$s=0;$a<12;)             // for loop x12 - both $a and $s equal 0
                                    // notice there is no incrementation and
                                    // no curly braces as there is just one
                                    // command to loop through

        $s+=$i[$a]*($a++%2?3:1);    // $s (sum) is being incremented by
                                    // $ath character of $i (auto-casted to
                                    // int) multiplied by 3 or 1, depending
                                    // wheter $a is even or not (%2 results
                                    // either 1 or 0, but 0 == FALSE)
                                    // $a is incremented here, using the
                                    // post-incrementation - which means that
                                    // it is incremented, but AFTER the value
                                    // is returned

    return$i.(10-$s%10)%10;         // returns $i with the check digit
                                    // attached - first it is %'d by 10,
                                    // then the result is subtracted from
                                    // 10 and finally %'d by 10 again (which
                                    // effectively just replaces 10 with 0)
                                    // % has higher priority than -, so there
                                    // are no parentheses around $s%10
}

Саме такий підхід я застосував у своїй відповіді C #. Здається, PHP на 9 символів більш ефективний!
Нелліус


5

Хаскелл, 78 71 66 символів

i s=s++(show$mod(2-sum(zipWith(*)(cycle[1,3])(map fromEnum s)))10)

5

Рубін - 73 65 годин

f=->s{s+((2-(s+s.gsub(/.(.)/,'\1')*2).bytes.inject(:+))%10).to_s}

"\\1"-> '\1'?
Nemo157

@Nemo, дякую, мій рубін трохи іржавий
gnibbler

Використовуйте синтаксис Ruby 1.9 f=->s{...}. Збережіть 6 символів. Також напишіть s<<(...).to_sзамість додавання 48 та використовуйте Fixnum#chr.
Hauleth

4

C # (94 символи)

string I(string i){int s=0,j=0;for(;j<12;)s+=(i[j]-48)*(j++%2<1?1:3);return i+((10-s%10)%10);}

За допомогою рядків / пробілів для читабельності:

string I(string i) 
{ 
    int s = 0, j = 0;
    for (; j < 12; )
        s += (i[j] - 48) * (j++ % 2 < 1 ? 1 : 3); 
    return i + ((10 - s % 10) % 10); 
}

Тестували на кількох номерах ISBN із книг на моїй полиці, тому я знаю, що це працює!


4

Пітон - 91 , 89

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|         |         |         |         |         |         |         |         |         |
 def c(i):return i+`(10-(sum(int(x)*3for x in i[1::2])+sum(int(x)for x in i[::2]))%10)%10`

Пробіли необов’язкові між першим аргументом та forinтретім) у розумінні списку, доки він може бути розділений парсером (не використовуючи ім’я змінної). -2 символи там.
Нік Т


4

C # - 89 77 символів

string I(string s){return s+(9992-s.Sum(x=>x-0)-2*s.Where((x,i)=>i%2>0).Sum(x=>x-0))%10;}

Відформатовано для читабельності:

string I(string s)
{
    return s +
            (9992
            - s.Sum(x => x - 0)
            - 2 * s.Where((x, i) => i%2 > 0).Sum(x => x - 0)
            ) % 10;
}

Ми не множимо на одне чи три, просто додаємо все, плюс додаємо всі парні символи ще раз, множимо на два.

9992 досить великий, щоб сума всіх символів ASCII була меншою, ніж (щоб ми могли модифікувати на 10 і бути впевненим, що результат позитивний, не потрібно модифікувати на 10 вдвічі), і не ділиться на нуль, тому що ми додаємо вгору всі додаткові 2 * 12 * 48 (дванадцять цифр ASCII, зважених на 1 і 3) == 1152, що дозволяє нам запастити один додатковий символ (замість того, щоб двічі відняти 48, ми віднімаємо 0 просто для перетворення з char в int, але замість 990 нам потрібно написати 9992).

Але знову ж таки, хоча і набагато менш красиво ;-), це старе шкільне рішення отримує нас до 80 символів (але це майже C-сумісно):

string T(string i){int s=2,j=0;for(;j<12;)s+=i[j]*(9-j++%2*2);return i+s%10;}

4

J - 55 45 38

f=:3 :'y,":10|10-10|+/(12$1 3)*"."0 y'

напр

f '978030640615'
9780306406157

старий спосіб:

f=:,":@(10(10&|@-)(10&|@+/@((12$1 3)*(i.12)&(".@{))))

1
(i.12)(".@{)yможна замінити на"."0 y
J Guy

3

Рубін - 80 символів

def f s;s+(10-s.bytes.zip([1,3]*6).map{|j,k|(j-48)*k}.inject(:+)%10).to_s[0];end

3

постійний струм, 44 ч

[d0r[I~3*rI~rsn++lndZ0<x]dsxx+I%Ir-I%rI*+]sI

Викликати як lIx, наприклад:

dc -e'[d0r[I~3*rI~rsn++lndZ0<x]dsxx+I%Ir-I%rI*+]sI' -e '978030640615lIxp'


2

D - 97 символів

auto f(string s){int n;foreach(i,c;s)n+=((i&1)*2+1)*(c-48);return s~cast(char)((10-n%10)%10+48);}

Відформатовано більш розбірливо:

auto f(string s)
{
    int n;

    foreach(i, c; s)
        n += ((i & 1) * 2 + 1) * (c - 48);

    return s ~ cast(char)((10 - n % 10) % 10 + 48);
}

Багатослівність оператора відливання D, безумовно, ускладнює написання нав’язливо короткого коду.


2

Java - 161 персонажів :(

int b[]=new int[a.length];
int d=0,n=0,j=1;
for(char c:a.toCharArray())b[d++]=Integer.valueOf(c+"");
for(int i:b)n+=(j++%2==0)?(i*3):(i*1);
return a+(10-(n%10));

Ця відповідь не відповідає першій вимозі, оскільки не є функцією.
Хан



1

C, 80 79 символів

Функція змінює рядок на місці, але повертає початковий вказівник рядка для задоволення проблемних вимог.

s;char*f(char*p){for(s=2;*p;s+=7**p++)s+=9**p++;*p++=48+s%10;*p=0;return p-13;}

Деякі пояснення: Замість віднімання 48 (значення ASCII цифри 0) від кожного вхідного символу акумулятор sініціалізується так, щоб він за модулем 10 був рівний 48 + 3 * 48 + 48 + 3 * 48 ... + 48 + 3 * 48 = 24 * 48 = 1152. Крок 10-sumможна уникнути, накопичуючи sвідніманням, а не додаванням. Однак оператор модуля %в C не дав би корисного результату, якби sбув негативним, тому замість використання s-=множників 3 і 1 замінюються на -3 = 7 по модулю 10 і -1 = 9 модуля 10 відповідно.

Тестовий джгут:

#include <stdio.h>
#define N 12
int main()
{
     char b[N+2];
     fgets(b, N+1, stdin);
     puts(f(b));
     return 0;
}

1

Groovy 75 , 66 chars

i={int i;it+(10-it.inject(0){t,c->t+(i++&1?:3)*(c as int)}%10)%10}

використання:

String z = "978030640615"
println i(z)

-> 9780306406157

1

APL (25)

{⍵,⍕10-10|+/(⍎¨⍵)×12⍴1,3}

Альго має закінчуватися 10 | бо в іншому випадку він може повернутись 10 на місці 0
RosLuP

1

Perl 6 , 29 байт

{$_~-:1[.comb «*»(1,3)]%10}

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


Тож підстава 1 може бути використана як заміна суми? Цікаво!
Джо Кінг

2
@JoKing Це насправді дуже стара хитрість у світі APL та J :)
Bubbler

Неправильний результат за 978186197371, схоже, 8, а не 9 ...
RosLuP

Вибачте, я думаю, що я вставив неправильний номер
RosLuP

1

Python 2 , 78 76 байт

lambda n:n+`10-(sum(int(a)+3*int(b)for a,b in zip(n[::2],n[1::2]))%10or 10)`

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

Приймає рядок як аргумент.

Пояснення:

Використовуючи позначення фрагмента python, перетворює рядок у список пар символів. ("978030640615" -> [("9", "7"), ("8", "0"), ("3", "0"), ("6", "4"), ("0 "," 6 "), (" 1 "," 5 ")])

Для цього списку пар перетворює кожен елемент у ціле число і повертає + 3b.

Підсумовує всі результати.

Отримує модуль суми 10, АБО 10, якщо решта дорівнює 0. (Це запобігає остаточній цифрі 10, а не 0.)

Вилучає решту з 10, щоб отримати контрольну цифру.

Перетворює обчислену контрольну цифру в рядок через застаріле вираження backtick.

Повертає початкове число плюс обчислену контрольну цифру.

Редагувати:

Збережено 2 баї, видаливши пробіли (дякую Джо Кінгу !).


Ви можете видалити пробіли до forіor
Jo King

Результатом для мене є те, що 978186197371 має останню цифру 8, а не 9 ... Я отримую це число з єдиного посилання, яке я друкую у своєму рішенні Apl
RosLuP

Вибачте, я думаю, що я вставив неправильне число ...
RosLuP

1

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

Функція анонімного мовчазного префікса, беручи рядок як аргумент. Використання підходу Bubbler .

⊢,∘⍕10|⍎¨+.×9 7⍴⍨≢

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

 довжина аргументу (12)

9 7⍴⍨ циклічно переробити [9,7]на таку довжину

+.× крапковий продукт наступного з цим:

⍎¨ `оцінювати кожного персонажа

10| мод-10 того

,∘⍕ передбачте наступну послідовність цього:

 немодифікований аргумент


1

DC , 25 байт

dn[A~9z^8+*rd0<M+]dsMxA%p

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

Я знаю, що тут вже є відповідь постійного струму, але 25 <44, тому я думаю, я відчуваю 19 байтів добре. Для цього використовується той факт, що 8+9^zеквівалентний -3або -1моду 10, залежно від того, чи є парне чи непарне. Тому я використовую A~для розбиття числа на цифри на стеці, але, будуючи стек, я помножую кожну цифру на 8+9^zде z - поточний розмір стека. Потім я додаю їх все як функція розгортає стека, і роздрукувати останню цифру.



0

R, 147 символів

f=function(v){s=as.numeric(strsplit(v,"")[[1]]);t=0;for(i in 1:12)if(i%%2==0)t=t+s[i]*3 else t=t+s[i];paste(v,(10-(t%%10))%%10,collapse="",sep="")}

Використання:

f("978030640615")
[1] "9780306406157"

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