Tính toán số kiểm tra ISBN-13


28

Viết một hàm, với 12 chữ số đầu tiên của mã ISBN-13 , sẽ tính toán toàn bộ ISBN thông qua tính toán và nối thêm một chữ số kiểm tra thích hợp.

Đầu vào của hàm của bạn là một chuỗi chứa 12 chữ số đầu tiên của ISBN. Đầu ra của nó là một chuỗi chứa tất cả 13 chữ số.

Đặc điểm kỹ thuật chính thức

Viết một hàm mà, khi đưa ra một chuỗi s bao gồm hoàn toàn chính xác 12 chữ số thập phân (và không có các nhân vật khác), trả về một chuỗi t với các thuộc tính sau:

  • t bao gồm chính xác 13 chữ số thập phân (và không có ký tự nào khác);
  • s là tiền tố của t ;
  • tổng của tất cả các chữ số ở các vị trí lẻ trong t (nghĩa là thứ nhất, thứ ba, thứ năm, v.v.), cộng với ba lần tổng của tất cả các chữ số ở các vị trí chẵn trong t (tức là thứ hai, thứ tư, thứ sáu, v.v.), là một bội số của 10.

Ví dụ / trường hợp thử nghiệm

Đầu vào
978030640615

Đầu ra
9780306406157

Điều kiện chiến thắng

Như một thử thách , câu trả lời ngắn nhất sẽ thắng.


1
Là đầu vào và đầu ra được cho là chứa dấu gạch ngang hoặc chỉ các chữ số?
sepp2k

1
Đã cập nhật mô tả, đầu vào và đầu ra chỉ là các chữ số
Kevin Brown

Có phải việc xuất ra đầy đủ ISBN-13 không?
Ông Llama

6
Lưu ý rằng các câu hỏi nên thực sự khép kín, vì vậy sẽ rất hữu ích nếu bao gồm một mô tả về thuật toán ở đây.
FlipTack

Đối với tôi, bài đăng trên đây rất kém về bài kiểm tra ví dụ ... Sẽ có 10 isbn cuối cùng và một trong số đó phải trả về 0 là chữ số cuối cùng ...
RosLuP

Câu trả lời:


14

Golfscript - 25 ký tự

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

Toàn bộ phiên bản chương trình chỉ có 19 ký tự

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

Kiểm tra lại ở đây để phân tích sau. Trong khi đó hãy kiểm tra câu trả lời cũ không mệt mỏi của tôi

Golfscript - 32 ký tự

Tương tự như cách tính số luhn

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

Phân tích cho YAM30640615

{...}: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'

Sau khi chạy mã thông qua trình thông dịch, tôi nghĩ bạn có thể lưu một số ký tự (trong giải pháp dựa trên Luhn 32 ký tự của bạn) bằng cách loại bỏ {ký tự đầu tiên và ba ký tự cuối cùng; }:f. Tôi tự hỏi liệu điều tương tự có thể được thực hiện cho giải pháp đầu tiên không ...
Rob

@MikeDtrick, những ký tự đó là cách GS định nghĩa một hàm. Phiên bản 19 char thực hiện những gì bạn đề xuất, nhưng câu hỏi yêu cầu "chức năng"
gnibbler

Oh okay, cảm ơn bạn đã giải thích.
Cướp

Bạn không cần :f(vâng, tôi biết các chức năng thường được đặt tên trước đó).
Erik the Outgolfer

8

Python - 44 ký tự

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

Python - 53 ký tự

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

Tôi nghĩ rằng f ('YAM306406159') xuất ra 'YAM3064061598' thay vì 'YAM306406157'
Mười

@Eelvex, chuỗi đầu vào phải luôn có 12 chữ số
gnibbler

À, bằng cách nào đó '9' lẻn vào. Xin lỗi ...
Mười

7

Haskell - 54 ký tự

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

Điều này đòi hỏi sự hỗ trợ cho việc hiểu danh sách song song , được hỗ trợ bởi GHC (với -XParallelListCompcờ) và Hugs (với -98cờ).


Bạn không cần bao gồm cờ đó trong số đếm? Bên cạnh đó, bạn có thể thay [1,3]bằng [9,7]và loại bỏ các -mà giúp bạn tiết kiệm một byte :)
ბიმო

7

APL (27 ký tự)

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

Tôi đang sử dụng Dyalog APL làm thông dịch viên. Đây là một lời giải thích nhanh, chủ yếu từ phải sang trái (trong định nghĩa hàm F←{ ... }):

  • ⍎¨⍵: Thực thi / đánh giá ( ) mỗi ¨ký tự ( ) được đưa ra trong đối số đúng ( ).
  • (12⍴1 3): Định hình lại ( ) vectơ 1 3thành một12 vectơ -element (lặp lại để lấp đầy các khoảng trống).
  • +.×: Lấy sản phẩm dấu chấm ( +.×) của đối số bên trái ( (12⍴1 3)) và đối số bên phải của nó ( ⍎¨⍵).
  • 10-: Trừ từ 10.
  • 10|: Tìm phần còn lại sau khi chia cho 10.
  • : Định dạng số (nghĩa là đưa ra một đại diện ký tự).
  • ⍵,: Nối ( ,) chữ số được tính toán của chúng tôi vào đúng đối số.

6

PHP - 86 85 82 ký tự

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

Định dạng lại và giải thích:

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
}

Chính xác là cách tiếp cận tôi đã thực hiện trong câu trả lời C # của mình. Có vẻ PHP là ~ 9 ký tự hiệu quả hơn!
Nellius

6

Windows PowerShell, 57

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

5

Haskell, 78 71 66 ký tự

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

5

Ruby - 73 65 ký tự

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

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

@Nemo, cảm ơn, viên ruby ​​của tôi hơi rỉ sét
gnibbler

Sử dụng cú pháp Ruby 1.9 f=->s{...}. Lưu 6 ký tự. Cũng viết s<<(...).to_sthay vì thêm 48 và sử dụng Fixnum#chr.
Hauleth

4

C # (94 ký tự)

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

Với ngắt dòng / khoảng trắng để dễ đọc:

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

Đã thử nghiệm trên một số ISBN từ sách trên giá của tôi, vì vậy tôi biết nó đang hoạt động!


4

Con trăn - 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`

Các không gian là tùy chọn giữa đối số đầu tiên và for(và inthứ ba) trong việc hiểu danh sách miễn là nó có thể được phân tách bởi trình phân tích cú pháp (không sử dụng tên biến). -2 ký tự ở đó.
Nick T

4

Perl, 53 ký tự

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

4

C # - 89 77 ký tự

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

Được định dạng để dễ đọc:

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

Chúng tôi không nhân với một hoặc ba, chúng tôi chỉ thêm mọi thứ, cộng với chúng tôi thêm tất cả các ký tự được đặt chẵn một lần nữa, nhân với hai.

9992 đủ lớn để tổng của tất cả các ký tự ASCII nhỏ hơn số đó (để chúng tôi có thể sửa đổi 10 và chắc chắn kết quả là dương, không cần phải sửa 10 lần) và không chia hết cho 0 vì chúng tôi thêm tăng thêm 2 * 12 * 48 (mười hai chữ số ASCII, có trọng số 1 và 3) == 1152, cho phép chúng tôi dự phòng thêm một ký tự (thay vì trừ hai lần 48, chúng tôi trừ 0 chỉ để chuyển đổi từ char sang int, nhưng thay vì 990, chúng ta cần viết 9992).

Nhưng sau đó, một lần nữa, mặc dù kém đẹp hơn nhiều ;-), giải pháp trường học cũ này đưa chúng ta tới 80 ký tự (nhưng điều này gần như tương thích với 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'

ví dụ

f '978030640615'
9780306406157

cách cũ:

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

1
(i.12)(".@{)ycó thể được thay thế bằng"."0 y
J Guy

3

Ruby - 80 ký tự

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

3

dc, 44 ký tự

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

Gọi như lIx, ví dụ:

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


2

D - 97 ký tự

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

Được định dạng rõ ràng hơn:

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ài của toán tử cast D chắc chắn làm cho việc viết mã ngắn một cách ám ảnh trở nên khó khăn hơn.


2

Java - 161 Ký tự :(

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

Câu trả lời này không thỏa mãn yêu cầu đầu tiên, vì nó không phải là một hàm.
han

1

Q (44 ký tự)

f:{x,string 10-mod[;10]0+/sum@'2 cut"I"$/:x}

Đây thực sự là không chính xác Tôi nghĩ rằng
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)

Kiểm tra:

val isbn="978030640615"
b(isbn)

Kết quả:

"9780306406157"

1

C, 80 79 ký tự

Hàm sửa đổi chuỗi tại chỗ, nhưng trả về con trỏ chuỗi gốc để đáp ứng các yêu cầu vấn đề.

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

Một số giải thích: Thay vì trừ 48 (giá trị ASCII của chữ số 0) từ mỗi ký tự đầu vào, bộ tích lũy sđược khởi tạo sao cho modulo 10 bằng 48 + 3 * 48 + 48 + 3 * 48 ... + 48 + 3 * 48 = 24 * 48 = 1152. Có 10-sumthể tránh bước này bằng cách tích lũy sbằng phép trừ thay vì cộng. Tuy nhiên, toán tử mô-đun %trong C sẽ không cho kết quả có thể sử dụng được nếus âm tính, vì vậy thay vì sử dụngs-= bội số 3 và 1 được thay thế bằng -3 = 7 modulo 10 và -1 = 9 modulo 10, tương ứng.

Khai thác thử nghiệm:

#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 ký tự

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

sử dụng:

String z = "978030640615"
println i(z)

-> 9780306406157

1

APL (25)

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

Algo phải kết thúc với 10 | bởi vì nó có thể trả về 10 ở vị trí 0
RosLuP

1

Perl 6 , 29 byte

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

Hãy thử trực tuyến!


Vậy cơ sở 1 có thể được sử dụng thay thế cho tổng? Hấp dẫn!
Jo King

2
@JoKing Đây thực sự là một mánh khóe rất cũ trong thế giới của APL và J :)
Bubbler

Kết quả sai cho Muff86197371 dường như là 8 chứ không phải 9 ...
RosLuP

Xin lỗi tôi nghĩ rằng tôi đã dán nhầm số
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)`

Hãy thử trực tuyến!

Lấy một chuỗi làm đối số.

Giải trình:

Sử dụng ký hiệu lát python, chuyển đổi một chuỗi thành một danh sách các cặp ký tự. ("YAM30640615" -> [("9", "7"), ("8", "0"), ("3", "0"), ("6", "4"), ("0" "," 6 "), (" 1 "," 5 ")])

Đối với danh sách các cặp đó, chuyển đổi từng mục thành một số nguyên và trả về + 3b.

Tổng hợp tất cả các kết quả.

Lấy tổng modulo 10, HOẶC 10 nếu phần còn lại bằng 0. (Điều này ngăn chữ số cuối cùng là 10 thay vì 0.)

Xóa phần còn lại từ 10 để lấy số kiểm tra.

Chuyển đổi chữ số kiểm tra được tính toán thành một chuỗi thông qua biểu thức backtick không dùng nữa.

Trả về số gốc cộng với số kiểm tra tính toán.

Chỉnh sửa:

Lưu 2 tạm biệt bằng cách xóa dấu cách (cảm ơn Jo King !).


Bạn có thể xóa các khoảng trắng trước foror
Jo King

Kết quả với tôi rằng Muff86197371 có chữ số 8 cuối cùng chứ không phải 9 ... Tôi nhận được số đó từ liên kết duy nhất tôi in trong giải pháp Apl của mình
RosLuP

Xin lỗi, tôi nghĩ rằng tôi đã dán nhầm số ...
RosLuP

1

APL (Dyalog Unicode) , 18 byte SBCS

Hàm tiền tố ẩn danh lấy chuỗi làm đối số. Sử dụng phương pháp của Bubbler .

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

Hãy thử trực tuyến!

 độ dài của đối số (12)

9 7⍴⍨ định hình lại theo chu kỳ theo [9,7]chiều dài đó

+.× chấm sản phẩm sau đây:

⍎¨ `đánh giá từng nhân vật

10| mod-10 trong số đó

,∘⍕ trả trước các chuỗi sau đây:

 đối số không được sửa đổi


1

dc , 25 byte

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

Hãy thử trực tuyến!

Tôi biết đã có câu trả lời dc ở đây, nhưng 25 <44 vì vậy tôi đoán tôi cảm thấy 19 byte ổn về nó. Điều này sử dụng thực tế 8+9^ztương đương với một trong hai -3hoặc -1mod 10 tùy thuộc vào việc z chẵn hay lẻ. Vì vậy, tôi sử dụng A~để chia số thành các chữ số trên ngăn xếp, nhưng khi tôi xây dựng ngăn xếp, tôi nhân mỗi chữ số với 8+9^zz là kích thước ngăn xếp hiện tại. Sau đó, tôi thêm tất cả chúng khi ngăn xếp chức năng ngăn chặn và in chữ số cuối cùng.


0

MATLAB - 82 ký tự

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

0

R, 147 ký tự

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

Sử dụng:

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

0

J, 25

,[:":10|0(-+/)"."0*1 3$~#
   f = :, [: ": 10 | 0 (- + /)". "0 * 1 3 $ ~ #
   f 'YAM30640615'
YAM306406406
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.