Hitung digit periksa ISBN-13

28

Tulis fungsi yang, mengingat 12 digit pertama dari kode ISBN-13 , akan menghitung seluruh ISBN melalui penghitungan dan menambahkan digit periksa yang sesuai.

Input fungsi Anda adalah string yang berisi 12 digit pertama ISBN. Outputnya adalah string yang berisi semua 13 digit.

Spesifikasi formal

Menulis fungsi yang, ketika diberi string s terdiri sepenuhnya dari tepat 12 angka desimal (dan tidak ada karakter lain), mengembalikan string t dengan sifat sebagai berikut:

  • t terdiri dari tepat 13 digit desimal (dan tidak ada karakter lain);
  • s adalah awalan t ;
  • jumlah semua digit dalam posisi ganjil dalam t (yaitu yang pertama, ketiga, kelima, dll.), ditambah tiga kali jumlah semua digit dalam posisi genap dalam t (yaitu yang kedua, keempat, keenam, dll), adalah kelipatan 10.

Contoh / test case

Memasukkan
978030640615

Keluaran
9780306406157

Kondisi kemenangan

Sebagai tantangan , jawaban terpendek menang.

Kevin Brown
sumber
1
Apakah input dan output seharusnya berisi tanda hubung atau hanya digit?
sepp2k
1
Diperbarui deskripsi, input dan output hanya digit
Kevin Brown
Apakah mengeluarkan ISBN-13 sepenuhnya dapat diterima juga?
Tn. Llama
6
Perhatikan bahwa pertanyaan harus benar-benar lengkap, sehingga akan sangat membantu untuk menyertakan deskripsi algoritma di sini.
FlipTack
Bagi saya posting di atas adalah contoh tes yang buruk ... Akan ada 10 isbn terakhir dan salah satunya harus mengembalikan 0 sebagai digit terakhir ...
RosLuP

Jawaban:

14

Golfscript - 25 karakter

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

Versi program keseluruhan hanya 19 karakter

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

Periksa kembali di sini untuk analisis nanti. Sementara itu periksa jawaban lama saya yang tidak terinspirasi

Golfscript - 32 karakter

Mirip dengan perhitungan angka luhn

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

Analisis untuk 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
sumber
Setelah menjalankan kode melalui penerjemah, saya pikir Anda dapat menyimpan beberapa karakter (dalam solusi berbasis Luhn 32 karakter Anda) dengan menyingkirkan karakter pertama {dan tiga terakhir; }:f. Saya ingin tahu apakah hal yang sama dapat dilakukan untuk solusi pertama ...
Rob
@MikeDtrick, karakter itu adalah bagaimana GS mendefinisikan suatu fungsi. Versi 19 char melakukan apa yang Anda sarankan, tetapi pertanyaannya meminta "fungsi"
gnibbler
Oh oke, terima kasih atas penjelasannya.
Rob
Anda tidak perlu :f(ya, saya tahu fungsi umumnya dinamai saat itu).
Erik the Outgolfer
8

Python - 44 karakter

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

Python - 53 karakter

def f(s):d=map(int,s);return s+`-sum(d+d[1::2]*2)%10`
gnibbler
sumber
Saya pikir f ('9780306406159') menghasilkan '97803064061598' bukan '9780306406157'
Eelvex
@Eelvex, string input harus selalu 12 digit
gnibbler
Ah, entah bagaimana '9' menyelinap masuk. Maaf ...
Eelvex
7

Haskell - 54 karakter

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

Ini membutuhkan dukungan untuk pemahaman daftar paralel , yang didukung oleh GHC (dengan -XParallelListCompbendera) dan Pelukan (dengan -98bendera).

Joey Adams
sumber
Apakah Anda tidak perlu menyertakan bendera itu dalam hitungan? Selain itu, Anda dapat mengganti [1,3]dengan [9,7]dan menghapus -byte yang menghemat :)
ბიმო
7

APL (27 karakter)

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

Saya menggunakan Dyalog APL sebagai penerjemah saya. Berikut penjelasan singkat, sebagian besar dari kanan ke kiri (dalam definisi fungsi, F←{ ... }):

  • ⍎¨⍵: Jalankan / evaluasi ( ) setiap ¨karakter ( ) yang diberikan dalam argumen yang benar ( ).
  • (12⍴1 3): Membentuk kembali ( ) vektor 1 3menjadi vektor - 12elemen (berulang untuk mengisi celah).
  • +.×: Ambil titik produk ( +.×) dari argumen kiri ( (12⍴1 3)) dan argumen kanannya ( ⍎¨⍵).
  • 10-: Kurangi dari 10.
  • 10|: Temukan sisanya setelah pembagian oleh 10.
  • : Format angka (mis., Berikan representasi karakter).
  • ⍵,: Tambahkan ( ,) digit terhitung kami ke argumen yang benar.
Dillon Cower
sumber
6

PHP - 86 85 82 karakter

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

Format ulang dan penjelasan:

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
}
Aurel Bílý
sumber
Tepatnya pendekatan yang saya ambil dalam jawaban C # saya. Sepertinya PHP ~ 9 karakter lebih efisien!
Nellius
6

Windows PowerShell, 57

filter i{$_+(990-($_-replace'(.)(.)','+$1+3*$2'|iex))%10}
Joey
sumber
5

Haskell, 78 71 66 karakter

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

Ruby - 73 65 karakter

f=->s{s+((2-(s+s.gsub(/.(.)/,'\1')*2).bytes.inject(:+))%10).to_s}
gnibbler
sumber
"\\1"-> '\1'?
Nemo157
@Nemo, terima kasih, ruby ​​saya agak berkarat
gnibbler
Gunakan sintaksis Ruby 1.9 f=->s{...}. Hemat 6 karakter. Juga tulis s<<(...).to_salih-alih menambahkan 48 dan gunakan Fixnum#chr.
Hauleth
4

C # (94 karakter)

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

Dengan linebreak / spasi putih untuk keterbacaan:

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

Diuji pada beberapa ISBN dari buku di rak saya, jadi saya tahu itu berfungsi!

Nellius
sumber
4

Python - 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
sumber
Spasi bersifat opsional antara argumen pertama dan for(dan indan ketiga) dalam pemahaman daftar selama itu dapat dibagi oleh parser (tidak menggunakan nama variabel). -2 karakter di sana.
Nick T
4

Perl, 53 karakter

sub i{$_=shift;s/(.)(.)/$s+=$1+$2*3/ge;$_.(10-$s)%10}
ninjalj
sumber
4

C # - 89 77 karakter

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

Diformat agar mudah dibaca:

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

Kami tidak mengalikan satu atau tiga, kami hanya menambahkan semuanya, ditambah kami menambahkan semua karakter genap sekali lagi, dikalikan dua.

9992 cukup besar sehingga jumlah semua karakter ASCII lebih kecil dari itu (sehingga kita dapat mod sebesar 10 dan pastikan hasilnya positif, tidak perlu mod sebanyak 10 kali), dan tidak dapat dibagi dengan nol karena kita menambahkan semua ekstra 2 * 12 * 48 (dua belas angka ASCII, ditimbang dengan 1 dan 3) == 1152, yang memungkinkan kita untuk menyimpan satu karakter tambahan (alih-alih dua kali mengurangi 48, kita kurangi 0 hanya untuk mengonversi dari char ke int, tetapi bukannya 990, kita perlu menulis 9992).

Tapi sekali lagi, meskipun jauh lebih tidak indah ;-), solusi old-school ini menghasilkan 80 karakter (tapi ini hampir kompatibel dengan 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
sumber
4

J - 55 45 38

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

misalnya

f '978030640615'
9780306406157

cara lama:

f=:,":@(10(10&|@-)(10&|@+/@((12$1 3)*(i.12)&(".@{))))
Eelvex
sumber
1
(i.12)(".@{)ydapat diganti dengan"."0 y
J Guy
3

Ruby - 80 karakter

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

dc, 44 karakter

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

Diminta sebagai lIx, misalnya:

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

Q, 36 karakter

{x,-3!10-mod[;10]sum(12#1 3)*"I"$'x}
tmartin
sumber
2

D - 97 karakter

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

Diformat lebih jelas:

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

Verbositas dari operator pemeran D pasti membuat lebih sulit untuk menulis kode pendek yang obsesif.

Jonathan M Davis
sumber
2

Java - 161 Karakter :(

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));
Oktavianus A. Damiean
sumber
Jawaban ini tidak memenuhi persyaratan pertama, karena ini bukan fungsi.
han
1

Q (44 karakter)

f:{x,string 10-mod[;10]0+/sum@'2 cut"I"$/:x}
skeevey
sumber
Ini sebenarnya salah saya pikir
skeevey
1

Scala 84

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

Pengujian:

val isbn="978030640615"
b(isbn)

Hasil:

"9780306406157"
Pengguna tidak diketahui
sumber
1

C, 80 79 karakter

Fungsi memodifikasi string di tempat, tetapi mengembalikan pointer string asli untuk memenuhi persyaratan masalah.

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

Beberapa penjelasan: Alih-alih mengurangi 48 (nilai ASCII digit 0) dari setiap karakter input, akumulator sdiinisialisasi sehingga modulo 10 sama dengan 48 + 3 * 48 + 48 + 3 * 48 ... + 48 + 3 * 48 = 24 * 48 = 1152. Langkah 10-sumini dapat dihindari dengan mengakumulasikan sdengan mengurangi bukannya menambah. Namun, operator modul %dalam C tidak akan memberikan hasil yang dapat digunakan jika snegatif, jadi alih-alih menggunakan s-=pengganda 3 dan 1 diganti dengan -3 = 7 modulo 10 dan -1 = 9 modulo 10, masing-masing.

Uji harness:

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

Groovy 75 , 66 karakter

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

menggunakan:

String z = "978030640615"
println i(z)

-> 9780306406157
Armand
sumber
1

APL (25)

{⍵,⍕10-10|+/(⍎¨⍵)×12⍴1,3}
marinus
sumber
Algo harus diakhiri dengan 10 | karena yang lain itu bisa mengembalikan 10 di tempat 0
RosLuP
1

Perl 6 , 29 byte

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

Cobalah online!

nwellnhof
sumber
Jadi basis 1 dapat digunakan sebagai pengganti jumlah? Menarik!
Jo King
2
@JoKing Sebenarnya ini adalah trik yang sangat lama di dunia APL dan J :)
Bubbler
Hasil yang salah untuk 978186197371 tampaknya menjadi 8 bukan 9 ...
RosLuP
Maaf, saya pikir saya telah menempelkan nomor yang salah
RosLuP
1

Python 2 , 78 76 byte

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

Cobalah online!

Mengambil string sebagai argumen.

Penjelasan:

Menggunakan notasi irisan python, mengubah string menjadi daftar pasangan karakter. ("978030640615" -> [("9", "7"), ("8", "0"), ("3", "0"), ("6", "4"), ("0 "," 6 "), (" 1 "," 5 ")])

Untuk daftar pasangan itu, konversi setiap item menjadi bilangan bulat dan mengembalikan +3b.

Jumlahkan semua hasil.

Mendapat jumlah modulo 10, OR 10 jika sisanya adalah 0. (Ini mencegah digit terakhir menjadi 10 bukannya 0.)

Hapus sisanya dari 10 untuk mendapatkan digit periksa.

Mengonversi digit periksa yang dihitung ke string melalui ekspresi backtick yang sudah usang.

Mengembalikan nomor asli ditambah digit periksa yang dihitung.

Edit:

Disimpan 2 byes dengan menghapus spasi (terima kasih Jo King !).

Triggernometri
sumber
Anda dapat menghapus spasi sebelumnya fordanor
Jo King
Hasil bagi saya bahwa 978186197371 memiliki digit terakhir 8 dan bukan 9 ... Saya mendapatkan nomor itu dari satu-satunya tautan yang saya cetak dalam solusi Apl saya
RosLuP
Maaf, saya pikir saya sudah menempelkan nomor yang salah ...
RosLuP
1

APL (Dyalog Unicode) , 18 byte SBCS

Fungsi awalan diam-diam anonim mengambil string sebagai argumen. Menggunakan pendekatan Bubbler .

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

Cobalah online!

 panjang argumen (12)

9 7⍴⍨ membentuk ulang secara siklis [9,7]sampai sejauh itu

+.× dot produk berikut ini dengan itu:

⍎¨ `mengevaluasi setiap karakter

10| mod-10 itu

,∘⍕ tambahkan berikut ini pengetatan itu:

 argumen yang tidak dimodifikasi

Adm
sumber
1

dc , 25 byte

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

Cobalah online!

Saya tahu sudah ada jawaban dc di sini, tapi 25 <44 jadi saya kira saya merasa 19 byte oke tentang hal itu. Ini menggunakan fakta yang 8+9^zsetara dengan mod -3atau -110 tergantung pada apakah z genap atau ganjil. Jadi saya gunakan A~untuk memecah angka menjadi angka-angka di tumpukan, tetapi ketika saya membangun tumpukan saya mengalikan setiap digit dengan di 8+9^zmana z adalah ukuran tumpukan saat ini. Kemudian saya menambahkan semuanya sebagai fungsi tumpukan membuka gulungan, dan mencetak digit terakhir.

Sophia Lechner
sumber
0

MATLAB - 82 karakter

function c(i)
[i num2str(mod(10-mod(sum(str2num(i(:)).*repmat([1;3],6,1)),10),10))]
Grifon
sumber
0

R, 147 karakter

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

Pemakaian:

f("978030640615")
[1] "9780306406157"
Paolo
sumber
0

J, 25

,[:":10|0(-+/)"."0*1 3$~#
   f =:, [: ": 10 | 0 (- + /)". "0 * 1 3 $ ~ #
   f '978030640615'
9780306406157
singkat
sumber