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.


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'

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`

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.


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.

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
}

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}

5

Haskell, 78 71 66 Zeichen

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

5

Ruby - 73 65 Zeichen

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

"\\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!


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`

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}

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

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)&(".@{))))

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

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'


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.


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

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}

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"

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

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

1

APL (25)

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

Das Algo muss mit 10 | enden weil es sonst 10 anstelle von 0 zurückgeben könnte
RosLuP


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 !).


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


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.


0

MATLAB - 82 Zeichen

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

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"

0

J, 25

,[:":10|0(-+/)"."0*1 3$~#
   f =:, [: ": 10 | 0 (- + /)". "0 * 1 3 $ ~ #
   f '978030640615'
9780306406157
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.