Рассчитать контрольную цифру ISBN-13

28

Напишите функцию, которая, учитывая первые 12 цифр кода ISBN-13 , будет вычислять весь ISBN путем вычисления и добавления соответствующей контрольной цифры.

Ввод вашей функции - это строка, содержащая первые 12 цифр номера ISBN. Его выводом является строка, содержащая все 13 цифр.

Формальная спецификация

Напишите функцию, которая при задании строки s, состоящей полностью из ровно 12 десятичных цифр (и без других символов), возвращает строку t со следующими свойствами:

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

Пример / тестовый пример

вход
978030640615

Выход
9780306406157

Состояние победы

В качестве победит самый короткий ответ.

Кевин Браун
источник
1
Предполагается, что вход и выход содержат тире или только цифры?
sepp2k
1
Обновил описание, ввод и вывод - только цифры
Кевин Браун
Является ли вывод полного ISBN-13 также приемлемым?
Мистер Лама
6
Обратите внимание, что вопросы должны быть самодостаточными, поэтому было бы полезно включить описание алгоритма здесь.
FlipTack
Для меня вышеупомянутый пост плохого примера теста ... Было бы, наконец, 10 isbn, и один из них должен вернуть 0 в качестве последней цифры ...
RosLuP

Ответы:

14

Golfscript - 25 символов

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

Всего версия программы всего 19 символов

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

Перепроверьте здесь для анализа позже. А пока посмотри мой старый скучный ответ

Golfscript - 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'
gnibbler
источник
После запуска кода через интерпретатор, я думаю, вы можете сохранить некоторые символы (в 32-символьном решении на основе Luhn), избавившись от первых {и последних трех символов; }:f, Интересно, можно ли сделать то же самое для первого решения ...
Роб
@MikeDtrick, эти символы - то, как GS определяет функцию. Версия с 19 символами делает то, что вы предлагаете, но вопрос задали для «функции»
gnibbler
О, хорошо, спасибо за объяснение.
Роб
Вам не нужно :f(да, я знаю, что функции обычно назывались тогда).
Эрик Outgolfer
8

Python - 44 символа

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

Python - 53 символа

def f(s):d=map(int,s);return s+`-sum(d+d[1::2]*2)%10`
gnibbler
источник
Я думаю, что f ('9780306406159') выводит '97803064061598' вместо '9780306406157'
Eelvex
@Eelvex, строка ввода всегда должна быть 12 цифр
gnibbler
Ах, каким-то образом «9»
проникло
7

Хаскель - 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 символов эффективнее!
Неллиус
6

Windows PowerShell, 57

filter i{$_+(990-($_-replace'(.)(.)','+$1+3*$2'|iex))%10}
детеныш
источник
5

Haskell, 78 71 66 символов

i s=s++(show$mod(2-sum(zipWith(*)(cycle[1,3])(map fromEnum s)))10)
sepp2k
источник
5

Рубин - 73 65 символов

f=->s{s+((2-(s+s.gsub(/.(.)/,'\1')*2).bytes.inject(:+))%10).to_s}
gnibbler
источник
"\\1"-> '\1'?
Nemo157
@Nemo, спасибо, мой рубин немного ржавый
gnibbler
Используйте синтаксис Ruby 1.9 f=->s{...}. Сохранить 6 символов. Также напишите s<<(...).to_sвместо добавления 48 и используйте Fixnum#chr.
Хаулет
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 из книг на моей полке, так что я знаю, что это работает!

Nellius
источник
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`
grokus
источник
Пробелы необязательны между первым аргументом и forinи третьим) в понимании списка, если он может быть разделен парсером (без использования имени переменной). -2 символа там.
Ник Т
4

Perl, 53 символа

sub i{$_=shift;s/(.)(.)/$s+=$1+$2*3/ge;$_.(10-$s)%10}
ninjalj
источник
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;}
Mormegil
источник
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)&(".@{))))
Eelvex
источник
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
Nemo157
источник
3

DC, 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'
ninjalj
источник
3

Q, 36 символов

{x,-3!10-mod[;10]sum(12#1 3)*"I"$'x}
tmartin
источник
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

Q (44 символа)

f:{x,string 10-mod[;10]0+/sum@'2 cut"I"$/:x}
skeevey
источник
Это на самом деле неправильно, я думаю
skeevey
1

Скала 84

def b(i:String)=i+(10-((i.sliding(2,2).map(_.toInt).map(k=>k/10+k%10*3).sum)%10)%10)

Тестирование:

val isbn="978030640615"
b(isbn)

Результат:

"9780306406157"
неизвестный пользователь
источник
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 символов

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
Armand
источник
1

APL (25)

{⍵,⍕10-10|+/(⍎¨⍵)×12⍴1,3}
Мэринус
источник
Альго должен заканчиваться 10 | потому что иначе он может вернуть 10 вместо 0
RosLuP
1

Perl 6 , 29 байт

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

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

nwellnhof
источник
Таким образом, база 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, чтобы получить контрольную цифру.

Преобразует вычисленную контрольную цифру в строку с помощью устаревшего выражения обратной галочки.

Возвращает исходное число плюс вычисленную контрольную цифру.

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

Сохранено 2 байса, удалив пробелы (спасибо Джо Кинг !).

Triggernometry
источник
Вы можете удалить пробелы до forиor
Джо Кинг
В результате мне 978186197371 имеет последнюю цифру 8, а не 9 ... Я получаю этот номер по единственной ссылке, которую я печатаю в своем решении
Apl
Извините, я думаю, что вставил не тот номер ...
RosLuP
1

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

Функция анонимного неявного префикса, принимающая строку в качестве аргумента. Используя подход Bubbler .

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

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

 длина аргумента (12)

9 7⍴⍨ циклически изменить [9,7]эту длину

+.× Точечный продукт следующего с этим:

⍎¨ оцените каждого персонажа

10| мод-10 этого

,∘⍕ добавьте следующую строку:

 неизмененный аргумент

Адам
источник
1

постоянный ток , 25 байтов

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

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

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

София Лехнер
источник
0

MATLAB - 82 символа

function c(i)
[i num2str(mod(10-mod(sum(str2num(i(:)).*repmat([1;3],6,1)),10),10))]
Грифон
источник
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"
Paolo
источник
0

J, 25

,[:":10|0(-+/)"."0*1 3$~#
   f =:, [: ": 10 | 0 (- + /)". "0 * 1 3 $ ~ #
   f '978030640615'
9780306406157
ephemient
источник