ISBN-13 Prüfziffer berechnen

28

Schreiben Sie eine Funktion , die anhand der ersten 12 Ziffern eines ISBN-13- Codes die gesamte ISBN berechnet, indem Sie eine entsprechende Prüfziffer berechnen und anhängen.

Die Eingabe Ihrer Funktion ist eine Zeichenfolge, die die ersten 12 Ziffern der ISBN enthält. Seine Ausgabe ist eine Zeichenfolge, die alle 13 Ziffern enthält.

Formale Spezifikation

Schreiben Sie eine Funktion, die bei einer Zeichenfolge s, die vollständig aus 12 Dezimalstellen (und keinen weiteren Zeichen) besteht, eine Zeichenfolge t mit den folgenden Eigenschaften zurückgibt :

  • t besteht aus genau 13 Dezimalstellen (und keinen weiteren Zeichen);
  • s ist ein Präfix von t ;
  • Die Summe aller Ziffern an ungeraden Stellen in t (dh die erste, dritte, fünfte usw.) plus das Dreifache der Summe aller Ziffern an geraden Stellen in t (dh die zweite, vierte, sechste usw.) ist a Vielfaches von 10.

Beispiel / Testfall

Eingang
978030640615

Ausgabe
9780306406157

Siegbedingung

Als Herausforderung gewinnt die kürzeste Antwort.

Kevin Brown
quelle
1
Sollen Ein- und Ausgabe Striche oder nur Ziffern enthalten?
1.
1
Aktualisierte die Beschreibung, die Eingabe und Ausgabe sind nur die Ziffern
Kevin Brown
Ist die Ausgabe der vollständigen ISBN-13 auch akzeptabel?
Mr. Llama
6
Beachten Sie, dass Fragen eigentlich in sich abgeschlossen sein sollten. Daher wäre es hilfreich, hier eine Beschreibung des Algorithmus aufzunehmen.
FlipTack
Für mich ist der obige Beitrag von
Testbeispiel

Antworten:

14

Golfscript - 25 Zeichen

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

Ganze Programmversion ist nur 19 Zeichen

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

Versuchen Sie es später noch einmal. In der Zwischenzeit checke meine alte, nicht inspirierte Antwort aus

Golfscript - 32 Zeichen

Ähnlich wie bei der Luhn-Zahlenberechnung

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

Analyse für 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'
Knabberzeug
quelle
Nachdem Sie den Code über einen Interpreter ausgeführt haben, können Sie einige Zeichen (in Ihrer auf 32 Zeichen basierenden Luhn-Lösung) speichern, indem Sie die ersten {und letzten drei Zeichen entfernen. }:f. Ich frage mich, ob das Gleiche für die erste Lösung getan werden kann ...
Rob
@ MikeDtrick, diese Zeichen sind, wie GS eine Funktion definiert. Die 19-Zeichen-Version macht, was Sie vorschlagen, aber die Frage nach einer "Funktion" gestellt
Knabber
Oh okay, danke für die Erklärung.
Rob
Sie brauchen das nicht :f(ja, ich weiß, dass Funktionen damals allgemein benannt wurden).
Erik the Outgolfer
8

Python - 44 Zeichen

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

Python - 53 Zeichen

def f(s):d=map(int,s);return s+`-sum(d+d[1::2]*2)%10`
Knabberzeug
quelle
Ich denke, f ('9780306406159') gibt '97803064061598' anstelle von '9780306406157' aus
Eelvex
@Eelvex, die Eingabezeichenfolge sollte immer 12-stellig sein
gnibbler
Ah, irgendwie hat sich '9' eingeschlichen. Entschuldigung ...
Eelvex
7

Haskell - 54 Zeichen

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

Dies erfordert Unterstützung für das parallele Listenverständnis , das von GHC (mit der -XParallelListCompFlagge) und Hugs (mit der -98Flagge) unterstützt wird.

Joey Adams
quelle
Müssen Sie dieses Flag nicht in die Zählung einbeziehen? Außerdem können Sie ersetzen [1,3]durch [9,7]und entfernen Sie die , -die Sie speichert ein Byte :)
ბიმო
7

APL (27 Zeichen)

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

Ich benutze Dyalog APL als Dolmetscher. Hier eine kurze Erklärung, meistens von rechts nach links (innerhalb der Funktionsdefinition F←{ ... }):

  • ⍎¨⍵: Führe jedes ( ¨) Zeichen aus, das im rechten Argument ( ) angegeben ist.
  • (12⍴1 3): Verwandle ( ) den Vektor 1 3in einen 12-Element-Vektor (Wiederholung, um die Lücken zu füllen).
  • +.×: Nehmen Sie das Skalarprodukt ( +.×) des linken Arguments ( (12⍴1 3)) und des rechten Arguments ( ⍎¨⍵).
  • 10-: Von 10 subtrahieren.
  • 10|: Finde den Rest nach Division durch 10.
  • : Formatieren Sie die Nummer (dh geben Sie eine Zeichendarstellung an).
  • ⍵,: Hänge ( ,) unsere berechnete Ziffer an das richtige Argument an.
Dillon Cower
quelle
6

PHP - 86 85 82 Zeichen

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

Neuformatierung und Erläuterung:

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ý
quelle
Genau die Annäherung, die ich in meiner C # -Antwort annahm. Scheint, PHP ist ~ 9 Zeichen effizienter!
Nellius
6

Windows PowerShell, 57

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

Haskell, 78 71 66 Zeichen

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

Ruby - 73 65 Zeichen

f=->s{s+((2-(s+s.gsub(/.(.)/,'\1')*2).bytes.inject(:+))%10).to_s}
Knabberzeug
quelle
"\\1"-> '\1'?
Nemo157
@Nemo, danke, mein Rubin ist ein bisschen rostig
Knabberzeug
Verwenden Sie die Ruby 1.9-Syntax f=->s{...}. Sparen Sie 6 Zeichen. Schreiben Sie auch, s<<(...).to_sanstatt 48 zu addieren, und verwenden Sie Fixnum#chr.
Hauleth
4

C # (94 Zeichen)

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

Mit Zeilenumbrüchen / Leerzeichen zur besseren Lesbarkeit:

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

Getestet mit mehreren ISBNs aus Büchern in meinem Regal, damit ich weiß, dass es funktioniert!

Nellius
quelle
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
quelle
Leerzeichen zwischen dem ersten Argument und for(und indem dritten) in einem Listenverständnis sind optional , solange es vom Parser aufgeteilt werden kann (ohne Verwendung eines Variablennamens). -2 Zeichen dort.
Nick T
4

Perl, 53 Zeichen

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

C # - 89 77 Zeichen

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

Zur besseren Lesbarkeit formatiert:

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

Wir multiplizieren nicht mit eins oder drei, wir addieren einfach alles und wir addieren alle geraden Zeichen noch einmal, multipliziert mit zwei.

9992 ist groß genug, damit die Summe aller ASCII-Zeichen kleiner ist (damit wir durch 10 modifizieren können und sicher sein können, dass das Ergebnis positiv ist, keine Notwendigkeit, durch 10 zweimal zu modifizieren) und nicht durch Null teilbar ist, weil wir addieren Addiere all diese zusätzlichen 2 * 12 * 48 (zwölf ASCII-Ziffern, gewichtet mit 1 und 3) == 1152, was uns erlaubt, ein zusätzliches Zeichen zu sparen (anstatt zweimal 48 zu subtrahieren, subtrahieren wir nur 0, um von char zu int zu konvertieren, aber statt 990 müssen wir 9992 schreiben).

Aber andererseits, obwohl viel weniger schön ;-), bringt uns diese Old-School-Lösung auf 80 Zeichen (aber das ist fast C-kompatibel):

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

J - 55 45 38

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

z.B

f '978030640615'
9780306406157

Alter Weg:

f=:,":@(10(10&|@-)(10&|@+/@((12$1 3)*(i.12)&(".@{))))
Eelvex
quelle
1
(i.12)(".@{)ykann ersetzt werden durch"."0 y
J Guy
3

Ruby - 80 Zeichen

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

dc, 44 Zeichen

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

Aufrufen als lIx, zB:

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

Q, 36 Zeichen

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

D - 97 Zeichen

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

Gut leserlicher formatiert:

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

Die Ausführlichkeit des Besetzungsoperators von D erschwert es auf jeden Fall, obsessiv kurzen Code zu schreiben.

Jonathan M Davis
quelle
2

Java - 161 Zeichen :(

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));
Octavian A. Damiean
quelle
Diese Antwort erfüllt nicht die erste Anforderung, da es sich nicht um eine Funktion handelt.
Han
1

Q (44 Zeichen)

f:{x,string 10-mod[;10]0+/sum@'2 cut"I"$/:x}
Skeevey
quelle
Das ist eigentlich falsch, denke ich
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)

Testen:

val isbn="978030640615"
b(isbn)

Ergebnis:

"9780306406157"
Benutzer unbekannt
quelle
1

C, 80 bis 79 Zeichen

Die Funktion ändert die vorhandene Zeichenfolge, gibt jedoch den ursprünglichen Zeichenfolgenzeiger zurück, um die Problemanforderungen zu erfüllen.

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

Einige Erklärungen: Anstatt 48 (den ASCII-Wert der Ziffer 0) von jedem eingegebenen Zeichen zu subtrahieren , wird der Akkumulator sso initialisiert, dass Modulo 10 gleich 48 + 3 * 48 + 48 + 3 * 48 ... + 48 + 3 ist * 48 = 24 * 48 = 1152. Der Schritt 10-sumkann vermieden werden, sindem anstelle der Addition durch Subtraktion akkumuliert wird. Der Moduloperator %in C würde jedoch kein verwertbares Ergebnis liefern, wenn ses negativ wäre. Anstatt s-=die Multiplikatoren 3 und 1 zu verwenden, werden diese durch -3 = 7 Modulo 10 bzw. -1 = 9 Modulo 10 ersetzt.

Testgeschirr:

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

Groovy 75 , 66 Zeichen

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

verwenden:

String z = "978030640615"
println i(z)

-> 9780306406157
Armand
quelle
1

APL (25)

{⍵,⍕10-10|+/(⍎¨⍵)×12⍴1,3}
Marinus
quelle
Das Algo muss mit 10 | enden weil es sonst 10 anstelle von 0 zurückgeben könnte
RosLuP
1

Perl 6 , 29 Bytes

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

Probieren Sie es online!

nwellnhof
quelle
So kann Basis 1 als Ersatz für die Summe verwendet werden? Interessant!
Jo King
2
@JoKing Es ist eigentlich ein sehr alter Trick in der Welt von APL und J :)
Bubbler
Falsches Ergebnis für 978186197371, es scheint 8, nicht 9 ...
RosLuP
Entschuldigung, ich glaube, ich habe die falsche Nummer
eingefügt
1

Python 2 , 78 76 Bytes

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

Probieren Sie es online!

Nimmt einen String als Argument.

Erläuterung:

Konvertiert mithilfe der Python-Slice-Notation eine Zeichenfolge in eine Liste von Zeichenpaaren. (978030640615 -> [(9, 7), (8, 0), (3, 0), (6, 4), (0 , 6), (1, 5)])

Konvertiert für diese Liste von Paaren jedes Element in eine Ganzzahl und gibt a + 3b zurück.

Summiert alle Ergebnisse.

Ruft die Summe Modulo 10 oder 10 ab, wenn der Rest 0 ist. (Dies verhindert, dass die letzte Ziffer 10 anstelle von 0 ist.)

Entfernt den Rest von 10, um die Prüfziffer zu erhalten.

Konvertiert die berechnete Prüfziffer über den veralteten Backtick-Ausdruck in eine Zeichenfolge.

Gibt die ursprüngliche Nummer plus die berechnete Prüfziffer zurück.

Bearbeiten:

2 Byes durch Entfernen von Leerzeichen gespeichert (danke Jo King !).

Triggernometrie
quelle
Sie können die Leerzeichen vor forund entfernenor
Jo King
Fazit für mich, dass 978186197371 die letzte Ziffer 8 und nicht 9 hat ... Ich erhalte diese Nummer aus dem einzigen Link, den ich in meiner Apl-Lösung
drucke
Entschuldigung, ich glaube, ich habe die falsche Nummer eingefügt ...
RosLuP
1

APL (Dyalog Unicode) , 18 Byte SBCS

Anonyme implizite Präfixfunktion, die Zeichenfolge als Argument verwendet. Mit Bubbler Ansatz .

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

Probieren Sie es online!

 Länge des Arguments (12)

9 7⍴⍨ zyklisch [9,7]auf diese Länge umformen

+.× Punktprodukt der folgenden damit:

⍎¨ `bewerte jedes Zeichen

10| mod-10 davon

,∘⍕ Stellen Sie Folgendes der Stringifizierung voran:

 das unveränderte Argument

Adam
quelle
1

Gleichstrom , 25 Bytes

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

Probieren Sie es online!

Ich weiß, dass es hier bereits eine DC-Antwort gibt, aber 25 <44, also denke ich, fühle ich mich mit 19 Bytes in Ordnung. Dies verwendet die Tatsache, dass 8+9^zentweder -3oder -1mod 10 äquivalent ist, abhängig davon, ob z gerade oder ungerade ist. Ich verwende also A~, um die Zahl in Ziffern auf dem Stapel aufzuteilen, aber wenn ich den Stapel aufbaue, multipliziere ich jede Ziffer mit 8+9^zwobei z die aktuelle Stapelgröße ist. Dann füge ich sie alle hinzu, während sich der Funktionsstapel abwickelt, und drucke die letzte Ziffer.

Sophia Lechner
quelle
0

MATLAB - 82 Zeichen

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

R, 147 Zeichen

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

Verwendung:

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

J, 25

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