Conversion d'ISBN-13 en ISBN-10


21

introduction

Dans ce défi, votre tâche consiste à générer le code ISBN-10 pour les livres étant donné son code ISBN-13, en supposant qu'un tel code existe. Un tel code ISBN-13 se compose de plusieurs parties séparées par -:

978-GG-PPPP-TTT-C

Les lettres G(groupe), P(éditeur), T(titre) et C(somme de contrôle) représentent toutes un chiffre. Aux fins de ce défi, le regroupement et le calcul de C(voir ce défi ) ne sont pas intéressants et nous allons supprimer tous les tirets pour simplifier cette tâche.

Un numéro ISBN-10 a une disposition très similaire:

GG-PPPP-TTT-c

Les lettres G, Pet Tsont les mêmes que pour l'ISBN à 13 chiffres, cependantc différentes (et sont calculées à l'aide d'un algorithme différent). Le chiffre cest choisi de manière à ce que l'équivalence suivante soit respectée (chiffres dans l'ordre):

10*G + 9*G + 8*P + … + 3*T + 2*T + 1*c = 0 (mod 11)

Exemple

Considérons le numéro ISBN 9780345391803: pour obtenir son code ISBN-10 correspondant, il suffit de supprimer le début 978et la somme de contrôle3 qui donne 034539180.

Ensuite, nous devons calculer la nouvelle somme de contrôle:

10*0 + 9*3 + 8*4 + 7*5 + 6*3 + 5*9 + 4*1 + 3*8 + 2*0 = 185

Le prochain nombre divisible par 11est 187, donc la nouvelle somme de contrôle est2 et donc le code ISBN-10 résultant 0345391802.

Règles

  • Votre entrée aura toujours un numéro ISBN-10 correspondant (c'est-à-dire qu'elle est exactement de 13 chiffres et commence par 978)
  • L'entrée ne doit pas nécessairement être un ISBN-13 valide (par exemple. 9780000000002)
  • Vous êtes assuré que l'ISBN résultant ne se terminera pas X
  • Vous pouvez prendre l'entrée comme un entier ou une chaîne (avec ou sans tirets), mais une liste de chiffres précalculés n'est pas autorisée
  • Votre sortie doit être un numéro ISBN-10 valide (avec ou sans tirets)
  • Votre sortie peut être un entier ou une chaîne (là encore aucune liste de chiffres)

Cas de test

9780000000002 -> 0000000000
9780201882957 -> 0201882957
9781420951301 -> 1420951300
9780452284234 -> 0452284236
9781292101767 -> 1292101768
9780345391803 -> 0345391802

Notez les zéros non significatifs!


5
Cela n'affecte pas du tout les solutions, mais juste pour être That Guy, votre description de la façon dont les parties d'un ISBN (-10 ou -13) sont séparées est incorrecte. L'élément de groupe d'enregistrement est de longueur variable et le nombre de chiffres pour les parties suivantes peut varier entre et au sein des groupes d'enregistrement. Par exemple, dans les deux 0-684-84328-5et 99921-58-10-7, la première partie ( 0et 99921respectivement) est le groupe d'inscription, la deuxième partie est l'éditeur, etc.
Jordan

5
10/10 exemples de choix ISBN
Jakob

Réponses:


10

Rétine ,  44  39 28 octets

>,L3,-2`.+
.
$.>`**
_{11}

_

Essayez-le en ligne!

Explication

Il est temps de montrer de nouvelles fonctionnalités Retina. :)

>,L3,-2`.+

Nous faisons correspondre l'intégralité de l'entrée avec .+, renvoyons cette correspondance L, mais ne sélectionnons que les caractères 3 (base zéro) à -2 (avant-dernier), inclus. Nous imprimons également le résultat sans retour à la ligne ( >).

Maintenant, soustraire des choses dans Retina est un peu ennuyeux. Mais heureusement, nous travaillons sur modulo 11, nous pouvons donc simplement inverser les coefficients de la combinaison linéaire (mod 11) et tout additionner. En d'autres termes, si la contrainte est:

10*G + 9*G + 8*P + … + 3*T + 2*T + 1*c = 0 (mod 11)

on obtient alors:

c = 1*G + 2*G + 3*P + … + 8*T + 9*T (mod 11)

Cela simplifie beaucoup les choses ici:

.
$.>`**

Nous remplaçons chaque personnage par cette chose en bas. *est l'opérateur de répétition de Retina. Il est associatif à droite et il a des opérandes implicites $&à gauche et _à droite, donc la substitution est en fait abrégée $.>`*$&*_. $&*_crée une chaîne de d soulignements, où d est le chiffre que nous remplaçons actuellement. Ensuite $.>`est la longueur de la chaîne jusqu'à et y compris le match. 1 Par conséquent, les résultats entiers d'expression dans une représentation unaire du n ième terme de notre combinaison linéaire.

_{11}

Faire le modulo réel est trivial en unaire: nous déposons simplement tous les ensembles complets de 11 traits de soulignement.

_

Enfin, nous comptons le nombre de soulignements restants et imprimons le résultat, ce qui complète l'ISBN-10.


1 Comment $.>`donne la longueur de la chaîne jusqu'au match inclus? Vous connaissez peut-être les $`substitutions d'expression régulière, ce qui vous donne la chaîne jusqu'à (mais à l'exclusion) la correspondance. En insérant a >, nous pouvons déplacer le contexte de la $`vers le séparateur entre la correspondance actuelle et la suivante (qui est une chaîne vide entre le chiffre actuel et le suivant). Ce séparateur $`inclura la correspondance actuelle. Il en $>`va de même pour l'écriture $`$&. Enfin, pour les $xéléments de substitution de tout type, Retina vous permet d'insérer un .après le $pour obtenir sa longueur.


Quelle est cette magie modulo 11?! Cela me fera économiser 4 octets ... mais je ne me gettit pas!
streetster

1
@streetster Fondamentalement, -2 ≡ 9 (mod 11)(parce que l'ajout ou la soustraction de 11 d'un nombre ne change pas sa "valeur" dans la classe de congruence mod 11). De plus, l'addition et la multiplication respectent les classes de congruence, vous pouvez donc remplacer n'importe quelle valeur dans une combinaison linéaire par une valeur équivalente sous le modulo actuel. La raison pour laquelle je parle de nombres négatifs est vraiment juste que j'ai réarrangé l'équation pour avoir cd'un côté et tous les autres termes (en tant que négatifs) de l'autre.
Martin Ender

Je pense que je comprends maintenant. Donc, vous vous déplacez cpour devenir -c = ...et plutôt que de multiplier par 10 9 8...vous soustrayez 11de chacun pour obtenir -1 -2 -3..., puis multipliez tout par -1 pour obtenir c.
streetster

Pourriez-vous expliquer pourquoi l'étape finale ne fait que remplacer les traits de soulignement de fin? J'ai passé un certain temps à essayer de comprendre ce qui est à l'origine de cela, mais je n'arrive pas à le reproduire. Au fait, cette mise à jour est incroyable, beau travail!
FryAmTheEggman

1
@FryAmTheEggman Merci :) À ce stade, la chaîne ne contient que des traits de soulignement. Nous avons déjà imprimé les neuf premiers chiffres de la première étape.
Martin Ender

6

05AB1E , 17 15 13 12 octets

¦¦¦¨DSƶO11%«

Essayez-le en ligne!

Explication

¦¦¦            # remove the first 3 characters
   ¨           # remove the last character
    D          # duplicate
     S         # split to list of digits
      ƶ        # multiply each by its 1-based index
       O       # sum
        11%    # mod by 11
           «   # concatenate

5

PowerShell , 96 84 octets

$y=-(([char[]]($x="$args"-replace'^978|.$')|%{--$a*[int]"$_"})-join'+'|iex)%11;$x+$y

Essayez-le en ligne!

Prend des entrées "$args", effectue une regex -replacepour obtenir uniquement la partie pertinente, stocke cela dans $xune chaîne. Ensuite, nous chartranscrivons cela en un tableau et parcourons chaque lettre. À l'intérieur de la boucle, nous pré-décrémentons$a (par défaut 0) et multiplions selon le calcul de la somme de contrôle. Notez la distribution àint , sinon cela utiliserait des valeurs ASCII.

Nous avons ensuite -joinces nombres avec +et le diriger vers iex( Invoke-Expressionet similaire à eval). Nous prenons cela %11et stockons cette somme de contrôle dans $y. Enfin, nous enchaînons les chaînes$x + $y et laissons cela dans le pipeline. La sortie est implicite.

Enregistré 12 octets grâce à Emigna.


Je ne connais pas vraiment le PowerShell, mais je pense que quelque chose comme ça peut fonctionner pour 84
Emigna

@Emigna Oui, bien sûr. L'arithmétique du module et mon cerveau ne fonctionnent pas bien.
AdmBorkBork

5

Octave , 46 41 39 37 octets

@(a)[c=a(4:12) 48+mod(7+c*(1:9)',11)]

Essayez-le en ligne!

Le code prend l'entrée sous forme de chaîne et renvoie une chaîne.

Le code se décompose comme suit:

@(a) crée une fonction anonyme.

Avec [c=a(4:12) ... ]nous extrayons les caractères qui forment le code principal, en enregistrant une copie dansc une utilisation ultérieure et ajoutons une autre copie à la chaîne de sortie finale.

Sur la base de @ manière intelligente de MartinEnter d'échange 10:-1:2dans 1:10, nous pouvons facilement générer cette gamme et la transposer pour obtenir un vecteur de colonne. c*(1:10)'effectue la multiplication de tableaux du vecteur ligne cet du vecteur colonne colonne. Cela revient à faire une multiplication par élément puis à additionner.

La somme de contrôle serait normalement mod(11-sum,11)de calculer le nombre requis pour que la somme soit un multiple de 11. Cependant, parce quec c'était une chaîne de caractères, la somme sera en fait plus grande qu'elle ne devrait l'être de 2592 (48 * 54) parce que nous l'avons multiplié par des nombres qui étaient 48 plus grandes que la valeur réelle.

Lorsque nous effectuons le modulo, il supprimera automatiquement tout sauf 7 de ce 2592. En tant que tel, et en tenant compte de la négation de la plage, le calcul réel devient 48+mod(7+sum,11). Nous ajoutons 48 au résultat pour reconvertir en caractère ASCII.

Le caractère de somme de contrôle est ajouté à la fin du résultat et la valeur renvoyée.


5

Gelée , 12 octets

ṫ4ṖȮV€xJS%11

Il s'agit d'un programme complet qui utilise des chaînes pour les E / S.

Essayez-le en ligne!

Comment ça marche

ṫ4ṖȮV€xJS%11  Main link. Argument: s (string of length 13)

ṫ4            Tail 4; discard the first three characters.
  Ṗ           Pop; discard the last characters.
   Ȯ          Output; print the result to STDOUT and return it.
    V€        Eval each; turn digit characters into digits.
       J      Indices; yield [1, ..., 13].
      x       Repeat the first digit once, the second digit twice, etc.
        S%11  Take the sum, modulo 11.
              (implicit) Print the checksum to STDOUT.

4

JavaScript (ES6), 59 56 octets

s=>(s=s.slice(3,-1))+[...s].reduce(n=>n+s[i++]*i,i=0)%11

-3 octets grâce à la suggestion de @ Shaggy .



1
Ou peut-être même 56 octets .
Shaggy

Alors pourquoi ne pas entrer sous forme de tableau de chiffres? 54 octets
tsh


3

Pyth , 16 octets

%s.e*ksbpP>Q3hT

Essayez-le ici!

Pyth , 17 octets

%s*VsMKpP>Q3SlK11

Essayez-le ici!

Explication

%s.e*hksbpP>Q3hT || Full program. Uses string for input and output.

            Q    || The input.
           > 3   || With elements at indexes smaller than 3 trimmed.
          P      || Pop (remove the last item).
         p       || Print the result without a linefeed, but also return it.
  .e             || Enumerated map. For each (index, value), assign two variables (k, b).
       sb        || b converted to an integer.
    *hk          || And multiplied by k + 1.
 s               || Summation.
%                || Modulo by:
               T || The literal 10.
              h  || Incremented by 1.

3

Japt , 16 15 octets

Je suis venu avec ça dans le pub l'autre soir et j'ai tout oublié.

s3J
U+¬x_*°TÃuB

Essayez-le


Pensez que vous pouvez enregistrer un octet avec s3JetU+¬x_*°TÃuB
ETHproductions

Bizarre; aurait juré que j'avais essayé ça. Merci, @ETHproductions.
Shaggy

Attends, non, j'avais oublié le U- D'oh!
Shaggy

3

Hexagonie , 77 61 octets

,,,,'~'11=\.A&.=\./';"-'"{4.8}}\'.A.>.,<\'+'%!@}/=+'+{./&{{&/

Essayez-le en ligne!


Coloré:


Voici une version plus grande. Il y a des croisements de chemins, mais parce que toutes ces cellules sont .(sans opération dans Hexagony), vous n'avez pas à vous en préoccuper:

(J'ai aussi essayé de garder les vieux miroirs, mais parfois j'ai besoin de changer quelque chose)

La commande linéaire exécutée est:

,,,,'48}}
,
while memory > 0:
    ';"-'"{+'+{=A&=''A
    if memory < 0:
        undefined behavior
    &{{&}
    ,
'"''+~'11='%!@

Explication: Au lieu de garder un compteur et de multiplier à chaque chiffre, ce programme:

  • conserver une variable "somme partielle" et une variable "somme totale" ( pet t)
  • pour chaque chiffre lu: ajoutez-le à la somme partielle et ajoutez la somme partielle à la somme totale.
  • imprimer (-p-t)%11, où %toujours retourner des résultats positifs.

3

K (oK) , 29 25 24 23 octets

Solution:

x,$11!7+/(1+!9)*x:-1_3_

Essayez-le en ligne!

Exemples:

x,$11!7+/(1+!9)*x:-1_3_"9780000000002"
"0000000000"
x,$11!7+/(1+!9)*x:-1_3_"9780345391803"
"0345391802"
x,$11!7+/(1+!9)*x:-1_3_"9781292101767"
"1292101768"
x,$11!7+/(1+!9)*x:-1_3_"9780452284234"
"0452284236"

Explication:

L'évaluation s'effectue de droite à gauche.

Deux astuces tirées d'autres solutions:

  • multiplier par 1 2 3 ... au lieu de 10 9 8 ...
  • multiplier les valeurs ASCII, puis ajouter 7 à la somme pour équilibrer

Panne:

x,$11!7+/(1+!9)*x:-1_3_ / the solution
                     3_ / drop three items from the start
                  -1_   / drop one item from the end
                x:      / save this as variable x
               *        / multiply by
         (    )         / all this together
            !9          / til, !9 => 0 1 2 3 4 5 6 7 8
          1+            / add 1 => 1 2 3 4 5 6 7 8 9
      7+/               / sum (+) over (/), start from 7
   11!                  / mod by 11
  $                     / convert back to a string
x,                      / join with x

Remarques:

  • -4 octets grâce à la magie " juste inverser les coefficients " de Martin Enders .
  • -1 octet merci à Tom Carpenter pour avoir supprimé la nécessité de convertir en nombres entiers (en ajoutant 7à la somme)
  • -1 octet démarre l'accumulateur à 7

3

C (gcc), 96 95 87 86 85 octets

(-1 grâce au plafond)

*f(s,r,c,d)char*s,*r;{for(d=13;--d;s+=*++s<48)r=d>8?c=3,s:r,c-=~d**s;*s=58-c%11;s=r;}

Essayez-le en ligne!

À appeler comme f(s), où sest un pointeur sur le premier élément d'un tableau de caractères modifiables. Modifie le tableau d'entrée, renvoie un pointeur dans le tableau d'entrée.




2

ECMAScript 6 , 86 67 octets

a=>(c=a.substr(3,9))+([...c].map(v=>g+=--i*v,e=i=g=11)?(e-g%e)%e:0)

Essayez-le en ligne!


Merci pour le commentaire d' Arnauld , passé de reduceà mapet débarrassé de returnmot - clé.


3
Bienvenue chez PPCG! Les réponses doivent être soit des programmes complets, soit des fonctions appelables (bien qu'elles puissent être des fonctions sans nom), pas seulement des extraits. Je crois que l'option la plus courte en JavaScript est généralement une lambda sans nom.
Martin Ender

@MartinEnder merci, j'ai édité ma réponse
Kos

3
Bienvenue à bord! Quelques conseils: l'initialisation variable peut généralement être mise en tant que paramètres supplémentaires de map(), reduce()etc. Avec une réécriture supplémentaire, il est souvent possible de se débarrasser de {}et return. De plus, dans ce cas particulier, il map()est probablement plus court que reduce(). ( Voici une version de 65 octets.)
Arnauld

Je suis sûr que ce f=n'est pas nécessaire. En outre, vous pouvez initialiser cà la propagation pour quelque chose comme ceci: a=>{i=10;s=[...c=a.substr(3,9)].reduce((g,v)=>+g+(i--)*v,0)%11;return c+=s?11-s:0}(-4 octets)
Asone Tuhid

2

Retina 0.8.2 , 72 51 octets

...(.*).
$1¶$1
r`.\G
$&$'
r`.\G
$*
1{11}

¶(1*)
$.1

Essayez-le en ligne!Parce que je n'ai pas encore appris Retina 1.0. Explication:

...(.*).
$1¶$1

Supprimez les caractères indésirables et faites une deuxième copie des chiffres appropriés.

r`.\G
$&$'

Suffixez chaque chiffre de la deuxième copie avec son suffixe. Cela répète efficacement chaque chiffre du suffixe par sa position.

r`.\G
$*

Convertissez les chiffres de la deuxième copie en unaire et ajoutez-les ensemble.

1{11}

Réduisez le module 11. (Il n'y a que 9 chiffres dans la première copie, cela ne peut donc jamais l'affecter.)

¶(1*)
$.1

Convertissez le résultat en décimal et supprimez à nouveau la nouvelle ligne.


2

APL (Dyalog Unicode) , 26 24 octets

∊⍕¨(⊢,11|⊢+.×⍳∘≢)3↓¯1↓⍎¨

Essayez-le en ligne!

Fonction de préfixe tacite. Prend l'entrée comme chaîne.

2 octets enregistrés grâce à @ngn.

Comment?

∊⍕¨(⊢,11|⊢+.×⍳∘≢)3↓¯1↓⍎¨     Main function.
                       ⍎¨     Execute each; turns the string into a vector of digits.
                 3↓¯1        Drop (↓) the last 1) and the first 3 digits.
   (           ≢)             Tally; returns the number of digits in the vector.
             ⍳∘                Then (∘) index (⍳) from 1
            ×                 Multiply the resulting vector [1..9]
         ⊢+.                  Dot product with sum with the original vector;
                              This will multiply both vectors, and sum the resulting vector.
      11|                     Mod 11
     ,                        Concatenate
                             With the original vector
 ⍕¨                           Format each; returns a vector of digits as strings.
                             Flatten to get rid of the spaces.


1

Kotlin , 83 octets

i.drop(3).dropLast(1).let{it+(11-(it.mapIndexed{i,c->(10-i)*(c-'0')}.sum()%11))%11}

Embellie

i.drop(3).dropLast(1).let {
    it + (11 - (it.mapIndexed { i, c -> (10 - i) * (c - '0') }.sum() % 11)) % 11
}

Tester

data class Test(val input: String, val output: String)

fun f(i: String) =

i.drop(3).dropLast(1).let{it+(11-(it.mapIndexed{i,c->(10-i)*(c-'0')}.sum()%11))%11}

val tests = listOf(
        Test("9780000000002", "0000000000"),
        Test("9780201882957", "0201882957"),
        Test("9781420951301", "1420951300"),
        Test("9780452284234", "0452284236"),
        Test("9781292101767", "1292101768"),
        Test("9780345391803", "0345391802")
)

fun main(args: Array<String>) {
    for (c in tests) {
        val answer = f(c.input)
        val good = answer == c.output
        println("$good ${c.input} -> ${c.output} | $answer")
    }
}

TIO

TryItOnline



1

PHP, 64 octets

Malheureusement, en PHP (-$c)%11est le même que -($c%11); donc je dois obtenir la différence à au moins la plus grande somme possible (55 * 9 = 495 = 45 * 11) au lieu de simplement utiliser -$c%11.

for($f=11;--$f>1;print$d)$c+=$f*$d=$argn[13-$f];echo(495-$c)%11;

ou

for($c=45*$f=11;--$f>1;print$d)$c-=$f*$d=$argn[13-$f];echo$c%11;

Exécuter en tant que pipe avec -nRou essayer en ligne .


0

Java 10, 110 octets

l->{var s=l+"";int c=0,i=3;for(;i<12;)c+=(13-i)*(s.charAt(i++)-48);return(l-(long)978e10)/10*10+(11-c%11)%11;}

Prend les entrées et les sorties sous forme d' longentier. Essayez-le en ligne ici .

Version non golfée:

l -> { // lambda taking a long as argument
    var s = l + ""; // convert the input to a String
    int c = 0, // the check digit
    i = 3; // variable for iterating over the digits
    for(; i < 12 ;) // go from the first digit past 978 to the one before the check digit
        c += (13 - i) * (s.charAt(i++) - 48); // calculate the check sum
    return (l - (long) 978e10) // remove the leading 978
           /10 *10 // remove the original check digit
           + (11 - c % 11) % 11; // add the new check digit
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.