คำนวณเลขเช็คไอ -13


28

เขียนฟังก์ชั่นซึ่งให้รหัส 12 หลักแรกของรหัสISBN-13จะคำนวณ ISBN ทั้งหมดผ่านการคำนวณและต่อท้ายตัวเลขการตรวจสอบที่เหมาะสม

การป้อนข้อมูลของฟังก์ชันของคุณคือสตริงที่มี 12 หลักแรกของ ISBN เอาท์พุทมันเป็นสตริงที่มีทั้งหมด 13 หลัก

ข้อกำหนดอย่างเป็นทางการ

เขียนฟังก์ชั่นซึ่งเมื่อได้รับสตริงsประกอบด้วยทศนิยมทั้งหมด 12 หลัก (และไม่มีอักขระอื่น ๆ ) ส่งคืนสตริงtด้วยคุณสมบัติดังต่อไปนี้:

  • tประกอบด้วยตัวเลขทศนิยม 13 หลัก (และไม่มีอักขระอื่น ๆ );
  • sเป็นคำนำหน้าของt ;
  • ผลรวมของตัวเลขทั้งหมดในตำแหน่งคี่ในt (เช่นที่หนึ่งที่สามที่สาม ฯลฯ ) บวกสามครั้งรวมของตัวเลขทั้งหมดที่อยู่ในตำแหน่งที่เท่ากันในt (เช่นที่สองที่สี่หกและอื่น ๆ ) เป็น หลาย 10

ตัวอย่าง / กรณีทดสอบ

อินพุต
978030640615

เอาท์พุต
9780306406157

เงื่อนไขชัยชนะ

ในฐานะที่เป็นความท้าทายของคำตอบที่สั้นที่สุดชนะ


1
อินพุตและเอาต์พุตควรมีเครื่องหมายขีดคั่นหรือเฉพาะตัวเลขหรือไม่?
sepp2k

1
อัปเดตคำอธิบายอินพุตและเอาต์พุตเป็นตัวเลขเท่านั้น
Kevin Brown

การส่งออก ISBN-13 แบบเต็มยอมรับได้หรือไม่?
Mr. Llama

6
โปรดทราบว่าคำถามควรมีอยู่ในตัวเองดังนั้นจึงเป็นประโยชน์หากรวมคำอธิบายของอัลกอริทึมที่นี่
FlipTack

สำหรับฉันโพสต์ข้างต้นไม่ดีของการทดสอบตัวอย่าง ... จะมีที่ 10 isbn ล่าสุดและหนึ่งในนั้นจะต้องกลับ 0 เป็นหลักสุดท้าย ...
RosLuP

คำตอบ:


14

Golfscript - 25 ตัวอักษร

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

เวอร์ชันโปรแกรมทั้งหมดมีเพียง 19 ตัวอักษร

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

โปรดกลับมาตรวจสอบที่นี่เพื่อทำการวิเคราะห์ในภายหลัง ตรวจสอบคำตอบที่ไม่มีคำตอบเก่าของฉัน

Golfscript - 32 ตัวอักษร

คล้ายกับการคำนวณหมายเลข luhn

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

หลังจากเรียกใช้รหัสผ่านล่ามฉันคิดว่าคุณสามารถบันทึกอักขระ (ในโซลูชันที่ใช้ Luhn 32 ตัวอักษร) โดยกำจัด{อักขระตัวแรกและตัวสุดท้ายสามตัว }:f. ฉันสงสัยว่าสิ่งเดียวกันสามารถทำได้สำหรับการแก้ปัญหาแรก ...
ร็อบ

@MikeDtrick ตัวละครเหล่านั้นเป็นวิธีที่ GS กำหนดฟังก์ชั่น รุ่น char 19 ทำในสิ่งที่คุณแนะนำ แต่คำถามที่ถามถึง "ฟังก์ชั่น"
gnibbler

โอเคขอบคุณสำหรับคำอธิบาย
Rob

คุณไม่ต้องการ:f(ใช่ฉันรู้ว่าฟังก์ชั่นถูกตั้งชื่อตามปกติแล้ว)
Erik the 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`

ฉันคิดว่า f ('9780306406159') เอาท์พุท '97803064061598' แทน '9780306406157'
Eelvex

@Elex สตริงอินพุตควรเป็น 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): Reshape ( ) เวกเตอร์1 3เป็น12เวกเตอร์องค์ประกอบ (ทำซ้ำเพื่อเติมเต็มช่องว่าง)
  • +.×: ใช้ผลิตภัณฑ์ dot ( +.×) ของอาร์กิวเมนต์ด้านซ้าย ( (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 อักขระ!
Nellius



5

Ruby - 73 65 ตัวอักษร

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

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

@Nemo ขอบคุณ ruby ​​ของฉันเป็นบิตสนิม
gnibbler

ใช้ทับทิม 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);}

ด้วย linebreaks / whitespace สำหรับการอ่าน:

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

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`

ช่องว่างเป็นทางเลือกระหว่างการโต้แย้งแรกและfor(และinที่สาม) ในรายการความเข้าใจตราบใดที่มันสามารถแยกโดย parser (ไม่ใช้ชื่อตัวแปร) -2 ตัวอักษรที่นั่น
Nick T


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 เพียงเพื่อแปลงจากอักขระเป็น 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 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

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'


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

การใช้คำฟุ่มเฟื่อยของตัวดำเนินการ cast ของ 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


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

APL (25)

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

อัลโกต้องจบด้วย 10 | เพราะมิฉะนั้นก็สามารถคืนค่า 10 แทน 0
RosLuP

1

Perl 6 , 29 ไบต์

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

ลองออนไลน์!


ดังนั้นฐาน 1 สามารถใช้แทนผลรวมได้หรือไม่ ! ที่น่าสนใจ
Jo King

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

ลองออนไลน์!

รับค่าสตริงเป็นอาร์กิวเมนต์

คำอธิบาย:

ใช้สัญกรณ์ส่วนหลามแปลงสตริงเป็นรายการคู่อักขระ ("978030640615" -> [("9", "7"), ("8", "0"), ("3", "0"), ("6", "4"), ("0 "," 6 "), (" 1 "," 5 ")])

สำหรับรายการคู่นั้นแปลงแต่ละรายการเป็นจำนวนเต็มและส่งกลับ +3b

ผลรวมทั้งหมด

รับผลรวมโมดูโล 10 หรือ 10 หากเศษเหลือเป็น 0 (นี่จะป้องกันไม่ให้เลขท้ายสุดท้ายเป็น 10 แทน 0)

ลบส่วนที่เหลือออกจาก 10 เพื่อรับตัวเลขเช็ค

แปลงตัวเลขตรวจสอบจากการคำนวณเป็นสตริงผ่านนิพจน์ backtick ที่เลิกใช้แล้ว

ส่งคืนหมายเลขเดิมพร้อมตัวเลขเช็คที่คำนวณได้

แก้ไข:

บันทึก 2 ไบต์ด้วยการลบช่องว่าง (ขอบคุณJo King !)


คุณสามารถลบช่องว่างก่อน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| mod-10 ของที่

,∘⍕ เสริมต่อไปนี้การทำให้เป็นสตริงของที่:

 อาร์กิวเมนต์ที่ไม่ได้แก้ไข


1

dc , 25 ไบต์

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

ลองออนไลน์!

ฉันรู้ว่ามีคำตอบอยู่ตรงนี้แล้ว แต่ 25 <44 ฉันเดาว่าฉันรู้สึกว่า 19 ไบต์ไม่เป็นไร สิ่งนี้ใช้ความจริงที่8+9^zเทียบเท่า-3หรืออย่างใดอย่างหนึ่ง-1mod 10 ขึ้นอยู่กับว่า z เป็นเลขคู่หรือคี่ ดังนั้นฉันจึงใช้A~เพื่อแบ่งตัวเลขออกเป็นตัวเลขบนสแต็ก แต่เมื่อฉันสร้างสแต็กฉันจะคูณแต่ละหลักด้วยโดย8+9^zที่ z คือขนาดสแต็กปัจจุบัน จากนั้นฉันจะเพิ่มพวกเขาทั้งหมดในขณะที่ฟังก์ชั่นสแต็ค unrolls และพิมพ์ตัวเลขสุดท้าย



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"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.