Conversión de ISBN-13 a ISBN-10


21

Introducción

En este desafío, su tarea es generar el código ISBN-10 para libros dado su código ISBN-13, suponiendo que dicho código exista. Tal código ISBN-13 consta de varias partes separadas por -:

978-GG-PPPP-TTT-C

Las letras G(grupo), P(editor), T(título) y C(suma de verificación) representan un dígito. Para el propósito de este desafío, la agrupación y el cálculo de C(ver este desafío ) no son interesantes y eliminaremos todos los guiones para simplificar esta tarea.

Un número ISBN-10 tiene un diseño muy similar:

GG-PPPP-TTT-c

Las letras G, Py Tson las mismas que para el ISBN de 13 dígitos, sin embargo, cson diferentes (y se calculan utilizando un algoritmo diferente). El dígito cse elige de tal manera que se cumpla la siguiente equivalencia (dígitos en orden):

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

Ejemplo

Consideremos el número ISBN 9780345391803: para obtener su código ISBN-10 correspondiente, simplemente eliminamos 978el 3rendimiento inicial y la suma de comprobación 034539180.

A continuación, debemos calcular la nueva suma de verificación:

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

El siguiente número divisible por 11es 187, entonces la nueva suma de verificación es 2y, por lo tanto, el código ISBN-10 resultante 0345391802.

Reglas

  • Su entrada siempre tendrá un número ISBN-10 correspondiente (es decir, tiene exactamente 13 dígitos y comienza con 978)
  • La entrada no necesariamente tiene que ser un ISBN-13 válido (p. Ej. 9780000000002)
  • Le garantizamos que el ISBN resultante no terminará con X
  • Puede tomar la entrada como un entero o cadena (con o sin guiones), sin embargo, no se permite una lista de dígitos calculada previamente
  • Su salida debe ser un número ISBN-10 válido (con o sin guiones)
  • Su salida puede ser un entero o una cadena (de nuevo, no hay listas de dígitos)

Casos de prueba

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

Tenga en cuenta los ceros a la izquierda!


55
No afecta en absoluto a las soluciones, pero solo por el hecho de ser ese tipo, su descripción de cómo se separan las partes de un ISBN (ya sea -10 o -13) es incorrecta. El elemento del grupo de registro es de longitud variable, y el número de dígitos para las partes posteriores puede variar entre los grupos de registro y dentro de ellos. Por ejemplo, en ambos 0-684-84328-5y 99921-58-10-7, la primera parte ( 0y 99921respectivamente) es el grupo de registro, la segunda parte es el editor, y así sucesivamente.
Jordan

55
10/10 ejemplos de opciones de ISBN
Jakob el

Respuestas:


10

Retina ,  44  39 28 bytes

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

_

Pruébalo en línea!

Explicación

Es hora de mostrar algunas nuevas características de Retina. :)

>,L3,-2`.+

Hacemos coincidir toda la entrada con .+, devolvemos esa coincidencia L, pero seleccionamos solo los caracteres 3 (basados ​​en cero) a -2 (penúltimo), inclusive. También imprimimos el resultado sin un salto de línea final ( >).

Ahora, restar cosas en Retina es un poco molesto. Pero afortunadamente, estamos trabajando en el módulo 11, por lo que podemos invertir los coeficientes de la combinación lineal (mod 11) y sumar todo. En otras palabras, si la restricción es:

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

entonces obtenemos:

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

Eso simplifica mucho las cosas aquí:

.
$.>`**

Reemplazamos cada personaje con esa cosa en la parte inferior. *es el operador de repetición de Retina. Es asociativo a la derecha y tiene operandos implícitos $&a la izquierda y _a la derecha, por lo que la sustitución es realmente la abreviatura de $.>`*$&*_. $&*_crea una serie de d guiones bajos, donde d es el dígito que actualmente estamos reemplazando. Luego $.>`es la longitud de la cadena hasta e incluyendo el partido. 1 Por lo tanto, toda la expresión da como resultado una representación unaria de la n º plazo de nuestra combinación lineal.

_{11}

Hacer el módulo real es trivial en unario: simplemente eliminamos todos los conjuntos completos de 11 guiones bajos.

_

Finalmente, contamos cuántos guiones bajos quedan e imprimimos el resultado, que completa el ISBN-10.


1 ¿Cómo $.>`da la longitud de la cuerda hasta e incluyendo el partido? Es posible que esté familiarizado con las $`sustituciones de expresiones regulares, que le dan la cadena hasta (pero excluyendo) la coincidencia. Al insertar a >, podemos cambiar el contexto de $`al separador entre la coincidencia actual y la siguiente (que es una cadena vacía entre el dígito actual y el siguiente). Ese separador $`incluirá la coincidencia actual. Entonces, $>`es una forma más corta de escribir $`$&. Finalmente, para todos los $xelementos de sustitución de tipo, Retina le permite insertar un .después del $para obtener su longitud.


¿Qué es este módulo 11 mágico? Eso me ahorrará 4 bytes ... ¡pero no lo consigo!
StreetSter

1
@streetster Básicamente, -2 ≡ 9 (mod 11)(porque sumar o restar 11 de un número no cambia su "valor" en la clase de congruencia mod 11). Y la suma y la multiplicación respetan las clases de congruencia, por lo que puede reemplazar cualquier valor en una combinación lineal con un valor equivalente bajo el módulo actual. La razón por la que estoy hablando de números negativos es realmente porque he reorganizado la ecuación para tenerla cen un lado y todos los demás términos (como negativos) en el otro.
Martin Ender

Creo que lo entiendo ahora. Entonces te mueves cpara convertirte -c = ...y, en lugar de multiplicar por 10 9 8..., restas 11de cada uno para obtener -1 -2 -3...y luego multiplicas todo por -1 para obtener c.
StreetSter

¿Te importaría explicar por qué la etapa final solo reemplaza los guiones bajos finales? He pasado un tiempo tratando de descubrir qué está causando eso, pero parece que no puedo reproducirlo. Por cierto, esta actualización se ve increíble, ¡buen trabajo!
FryAmTheEggman

1
@FryAmTheEggman Gracias :) En ese momento, la cadena contiene solo guiones bajos. Ya hemos impreso los primeros nueve dígitos en la primera etapa.
Martin Ender

6

05AB1E , 17 15 13 12 bytes

¦¦¦¨DSƶO11%«

Pruébalo en línea!

Explicación

¦¦¦            # 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 bytes

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

Pruébalo en línea!

Toma entrada "$args", hace una expresión regular -replacepara obtener solo la parte pertinente, la almacena $xcomo una cadena. Luego lo lanzamos como una charmatriz y recorremos cada letra. Dentro del bucle, pre-decrementamos $a(que por defecto es 0) y multiplicamos de acuerdo con el cálculo de la suma de verificación. Tenga en cuenta la conversión a int, de lo contrario esto usaría valores ASCII.

Luego -joinjuntamos esos números +y los canalizamos a iex( Invoke-Expressiony similares a eval). Tomamos eso %11y almacenamos esa suma de verificación $y. Finalmente, encadenamos $x + $yy dejamos eso en la tubería. La salida es implícita.

Guardado 12 bytes gracias a Emigna.


Realmente no conozco PowerShell, pero creo que algo como esto puede funcionar para 84
Emigna

@Emigna Sí, por supuesto. La aritmética del módulo y mi cerebro no funcionan bien.
AdmBorkBork

5

Octava , 46 41 39 37 bytes

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

Pruébalo en línea!

El código toma la entrada como una cadena y devuelve una cadena.

El código se descompone de la siguiente manera:

@(a) Crea una función anónima.

Con [c=a(4:12) ... ]extraemos los caracteres que forman el código principal, guardamos una copia cpara su uso posterior y agregamos otra copia a la cadena de salida final.

Sobre la base de @ forma inteligente de MartinEnter de intercambiar 10:-1:2en 1:10, podemos generar fácilmente ese rango y la transposición a obtener un vector columna. c*(1:10)'hace una multiplicación de matriz del vector de fila cy del vector de columna de rango. Esto es equivalente a hacer una multiplicación por elementos y luego sumar.

La suma de verificación normalmente sería mod(11-sum,11)calcular el número requerido para que la suma sea un múltiplo de 11. Sin embargo, debido a que cera una cadena de caracteres, la suma en realidad será mayor de lo que debería ser por 2592 (48 * 54) porque multiplicamos por números que eran 48 más grandes que el valor real.

Cuando realizamos el módulo, eliminará automáticamente todos menos 7 de ese 2592. Como tal, y teniendo en cuenta la negación del rango, el cálculo real se convierte 48+mod(7+sum,11). Agregamos 48 al resultado para volver a convertirlo en un carácter ASCII.

El carácter de suma de comprobación se agrega al final del resultado y se devuelve el valor.


5

Jalea , 12 bytes

ṫ4ṖȮV€xJS%11

Este es un programa completo que utiliza cadenas para E / S.

Pruébalo en línea!

Cómo funciona

ṫ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 bytes

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

-3 bytes gracias a la sugerencia de @ Shaggy .



1
O tal vez incluso 56 bytes .
Shaggy

Entonces, ¿por qué no ingresar como conjunto de dígitos? 54 bytes
tsh


3

Pyth , 16 bytes

%s.e*ksbpP>Q3hT

Pruébalo aquí!

Pyth , 17 bytes

%s*VsMKpP>Q3SlK11

Pruébalo aquí!

Explicación

%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 bytes

Se me ocurrió esto en el pub la otra noche y lo olvidé por completo.

s3J
U+¬x_*°TÃuB

Intentalo


Creo que puede guardar un byte con s3JyU+¬x_*°TÃuB
ETHproductions

Extraño; podría haber jurado que lo había intentado. Gracias, @ETHproductions.
Shaggy

Espera, no, me había olvidado de U... ¡Oh!
Shaggy

3

Hexagonía , 77 61 bytes

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

Pruébalo en línea!


De colores:


Aquí hay una versión más grande. Hay algunos cruces de ruta, pero porque todas esas celdas son. (no operativas en Hexagony), no necesita preocuparse por ellas:

(También traté de mantener los viejos espejos, pero a veces necesito cambiar algo)

El comando lineal ejecutado es:

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

Explicación: en lugar de mantener un contador y multiplicar cada dígito, este programa:

  • mantener una variable de "suma parcial" y una variable de "suma total" ( py t)
  • para cada dígito leído: agréguelo a la suma parcial y agregue la suma parcial a la suma total.
  • print (-p-t)%11, donde %siempre devuelve resultados positivos.

3

K (oK) , 29 25 24 23 bytes

Solución:

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

Pruébalo en línea!

Ejemplos:

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"

Explicación:

La evaluación se realiza de derecha a izquierda.

Dos trucos tomados de otras soluciones:

  • multiplicar por 1 2 3 ... en lugar de 10 9 8 ...
  • multiplique los valores ASCII y luego agregue 7 a la suma para equilibrar

Descompostura:

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

Notas:

  • -4 bytes gracias a Martin Enders " simplemente invierte los coeficientes magia de ".
  • -1 byte gracias a Tom Carpenter por eliminar la necesidad de convertir a enteros (agregando 7a la suma)
  • -1 byte inicia el acumulador a las 7

3

C (gcc) 96 95 87 86 85 bytes

(-1 gracias a ceilingcat)

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

Pruébalo en línea!

Para ser llamado como f(s), donde ses un puntero al primer elemento de una matriz de caracteres modificables. Modifica la matriz de entrada, devuelve un puntero en la matriz de entrada.




2

ECMAScript 6 , 86 67 bytes

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

Pruébalo en línea!


Gracias por el comentario de Arnauld , cambiaron de reducea mapy se deshicieron de returnla palabra clave.


3
Bienvenido a PPCG! Las respuestas deben ser programas completos o funciones invocables (aunque pueden ser funciones sin nombre), no solo fragmentos. Creo que la opción más corta en JavaScript suele ser una lambda sin nombre.
Martin Ender

@MartinEnder gracias, he editado mi respuesta
Kos

3
¡La bienvenida a bordo! Algunos consejos: La inicialización variable generalmente se puede poner como parámetros adicionales de map(), reduce()etc. Con alguna reescritura adicional, a menudo es posible deshacerse de {}y return. Además, en este caso particular, map()es probablemente más corto que reduce(). ( Aquí hay una versión de 65 bytes.)
Arnauld

Estoy bastante seguro de f=que no es necesario. Además, puede inicializar cen el spread para algo como esto: a=>{i=10;s=[...c=a.substr(3,9)].reduce((g,v)=>+g+(i--)*v,0)%11;return c+=s?11-s:0}(-4 bytes)
Asone Tuhid

2

Retina 0.8.2 , 72 51 bytes

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

¶(1*)
$.1

Pruébalo en línea! Porque todavía no he aprendido Retina 1.0. Explicación:

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

Elimine los caracteres no deseados y haga una segunda copia de los dígitos apropiados.

r`.\G
$&$'

Sufije cada dígito en la segunda copia con su sufijo. Esto efectivamente repite cada dígito en el sufijo por su posición.

r`.\G
$*

Convierta los dígitos en la segunda copia a unario y así sumarlos.

1{11}

Reduzca el módulo 11. (Solo hay 9 dígitos en la primera copia, por lo que esto nunca puede afectarlo).

¶(1*)
$.1

Convierta el resultado a decimal y elimine la nueva línea nuevamente.


2

APL (Dyalog Unicode) , 26 24 bytes

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

Pruébalo en línea!

Función de prefijo tácito. Toma la entrada como cadena.

2 bytes guardados gracias a @ngn.

¿Cómo?

∊⍕¨(⊢,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 bytes

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

Embellecido

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

Prueba

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 bytes

Lamentablemente, en PHP (-$c)%11es lo mismo que -($c%11); así que tengo que obtener la diferencia al menos a la mayor suma posible (55 * 9 = 495 = 45 * 11) en lugar de simplemente usarla -$c%11.

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

o

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

Ejecutar como tubería -nRo probarlos en línea .


0

Java 10, 110 bytes

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

Toma entradas y salidas como un longentero. Pruébelo en línea aquí .

Versión sin golf:

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
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.