Conversione di ISBN-13 in ISBN-10


21

introduzione

In questa sfida il tuo compito è generare il codice ISBN-10 per i libri dato il suo codice ISBN-13, supponendo che esista un codice del genere. Tale codice ISBN-13 è composto da più parti separate da -:

978-GG-PPPP-TTT-C

Le lettere G(gruppo), P(editore), T(titolo) e C(checksum) rappresentano tutte una cifra. Ai fini di questa sfida, il raggruppamento e il calcolo di C(vedi questa sfida ) non sono interessanti e abbandoneremo tutti i trattini per semplificare questo compito.

Un numero ISBN-10 ha un layout molto simile:

GG-PPPP-TTT-c

Le lettere G, Pe Tsono le stesse del codice ISBN a 13 cifre, tuttavia csono diverse (e vengono calcolate utilizzando un algoritmo diverso). La cifra cviene scelta in modo tale che valga la seguente equivalenza (cifre in ordine):

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

Esempio

Consideriamo il numero ISBN 9780345391803: per ottenere il suo codice ISBN-10 corrispondente abbiamo semplicemente cadere il leader 978e il checksum 3cedimento 034539180.

Successivamente è necessario calcolare il nuovo checksum:

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

Il prossimo numero divisibile per 11è 187, quindi il nuovo checksum è 2e quindi il codice ISBN-10 risultante 0345391802.

Regole

  • Il tuo input avrà sempre un corrispondente codice ISBN-10 (cioè è lungo esattamente 13 cifre e inizia con 978)
  • L'input non deve necessariamente essere un codice ISBN-13 valido (ad es. 9780000000002)
  • Hai la garanzia che il codice ISBN risultante non finirà con X
  • È possibile accettare input come numero intero o stringa (con o senza trattini), tuttavia non è consentito un elenco precompilato di cifre
  • L'output deve essere un numero ISBN-10 valido (con o senza trattini)
  • L'output può essere un numero intero o una stringa (di nuovo nessun elenco di cifre)

Casi test

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

Nota gli zeri iniziali!


5
Non influisce affatto sulle soluzioni, ma solo per essere quel tipo, la descrizione di come le parti di un codice ISBN (-10 o -13) sono separate non è corretta. L'elemento del gruppo di registrazione ha una lunghezza variabile e il numero di cifre per le parti successive può variare tra e all'interno dei gruppi di registrazione. Ad esempio, in entrambi 0-684-84328-5e 99921-58-10-7, la prima parte ( 0e 99921rispettivamente) è il gruppo di registrazione, la seconda parte è l'editore e così via.
Giordania,

5
10/10 esempi di scelte ISBN
Jakob

Risposte:


10

Retina ,  44  39 28 byte

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

_

Provalo online!

Spiegazione

È ora di mostrare alcune nuove funzionalità di Retina. :)

>,L3,-2`.+

Abbiniamo l'intero input a .+, restituiamo quella corrispondenza L, ma selezioniamo solo i caratteri da 3 (a base zero) a -2 (penultimo), inclusi. Stampiamo anche il risultato senza un trascinamento di riga ( >).

Sottrarre cose in Retina è un po 'fastidioso. Ma per fortuna, stiamo lavorando al modulo 11, quindi possiamo semplicemente invertire i coefficienti della combinazione lineare (mod 11) e aggiungere tutto. In altre parole, se il vincolo è:

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

quindi otteniamo:

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

Questo semplifica molto le cose qui:

.
$.>`**

Sostituiamo ogni personaggio con quella cosa in fondo. *è l'operatore di ripetizione di Retina. È associativo di destra e ha operandi impliciti $&a sinistra e _a destra, quindi la sostituzione è effettivamente abbreviata $.>`*$&*_. $&*_crea una serie di d sottolineature, dove d è la cifra al momento stiamo sostituendo. Quindi $.>`è la lunghezza della stringa fino a e compresa la corrispondenza. 1 Quindi, l'intero risultato di espressione in una rappresentazione unaria di n esimo termine di una combinazione lineare.

_{11}

Fare il modulo attuale è banale in unario: lasciamo cadere tutti i set completi di 11 caratteri di sottolineatura.

_

Infine, contiamo quanti caratteri di sottolineatura rimangono e stampiamo il risultato, che completa il codice ISBN-10.


1 In che modo $.>`la lunghezza della stringa può essere compresa e compresa la corrispondenza? Potresti avere familiarità con le $`sostituzioni regex, che ti danno la stringa fino a (ma escludendo) la corrispondenza. Inserendo a >, possiamo spostare il contesto del $`al separatore tra la corrispondenza corrente e la successiva (che è una stringa vuota tra la cifra corrente e la successiva). Quel separatore $`includerà la corrispondenza corrente. Quindi $>`è un modo più breve di scrivere $`$&. Infine, per tutti gli $xelementi di sostituzione di tipo, Retina ti consente di inserire un .after $per ottenere la sua lunghezza.


Cos'è questo modulo 11 magico ?! Questo mi farà risparmiare 4 byte ... ma non ci riesco!
streetster

1
@streetster Fondamentalmente, -2 ≡ 9 (mod 11)(perché l'aggiunta o la sottrazione di 11 da un numero non cambia il suo "valore" nella classe di congruenza mod 11). Inoltre, l'addizione e la moltiplicazione rispettano le classi di congruenza, quindi è possibile sostituire qualsiasi valore in una combinazione lineare con un valore equivalente nel modulo corrente. Il motivo per cui sto parlando di numeri negativi è proprio il fatto che ho riorganizzato l'equazione da avere cda una parte e tutti gli altri termini (come negativi) dall'altra.
Martin Ender,

Io penso che ho capito ora. Quindi ti sposti cper diventare -c = ...e piuttosto che moltiplicare per 10 9 8...sottrarre 11da ciascuno per ottenere -1 -2 -3...e quindi moltiplicare tutto per -1 per ottenere c.
streetster

Ti dispiacerebbe spiegare perché la fase finale sta sostituendo solo i trattini bassi finali? Ho passato un po 'a cercare di capire cosa lo sta causando, ma non riesco a riprodurlo. Questo aggiornamento sembra incredibile, bel lavoro!
FryAmTheEggman,

1
@FryAmTheEggman Grazie :) A quel punto, la stringa contiene solo caratteri di sottolineatura. Abbiamo già stampato le prime nove cifre nella prima fase.
Martin Ender,

6

05AB1E , 17 15 13 12 byte

¦¦¦¨DSƶO11%«

Provalo online!

Spiegazione

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

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

Provalo online!

Prende input "$args", fa una regex -replaceper ottenere solo la parte pertinente, la memorizza $xcome una stringa. Quindi lo charlanciamo come una matrice e attraversiamo ogni lettera. All'interno del loop, pre-decrementiamo $a(impostazione predefinita 0) e moltiplichiamo secondo il calcolo del checksum. Nota il cast su int, altrimenti questo userebbe i valori ASCII.

Abbiamo quindi -joinquei numeri insieme +e reindirizziamo a iex( Invoke-Expressione simili a eval). Lo prendiamo %11e archiviamo quel checksum $y. Infine, concateniamo la stringa $x + $ye la lasciamo sulla pipeline. L'output è implicito.

Risparmiato 12 byte grazie a Emigna.


Io non so davvero PowerShell, ma penso che qualcosa di simile a questo può funzionare per 84
Emigna

@Emigna Sì, certo. L'aritmetica dei moduli e il mio cervello non giocano bene.
AdmBorkBork,

5

Ottava , 46 41 39 37 byte

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

Provalo online!

Il codice accetta l'input come stringa e restituisce una stringa.

Il codice si suddivide come segue:

@(a) crea una funzione anonima.

Con [c=a(4:12) ... ]estraiamo i caratteri che formano il codice principale, salvandone una copia cper un uso successivo e aggiungendo un'altra copia alla stringa di output finale.

Sulla base di @ modo intelligente di MartinEnter di scambiare 10:-1:2in 1:10, si può facilmente generare tale intervallo e trasporre per ottenere un vettore colonna. c*(1:10)'esegue la moltiplicazione di array del vettore riga ce del vettore colonna intervallo. Ciò equivale a fare una moltiplicazione in base all'elemento, quindi sommare.

Il checksum sarebbe normalmente quello mod(11-sum,11)di calcolare il numero richiesto per la somma di un multiplo di 11. Tuttavia, poiché cera una stringa di caratteri, la somma sarà effettivamente più grande di quanto dovrebbe essere per 2592 (48 * 54) perché abbiamo moltiplicato per i numeri che erano 48 più grandi del valore reale.

Quando eseguiamo il modulo, si eliminerà automaticamente tutto tranne 7 di quel 2592. Come tale, e tenendo conto della negazione dell'intervallo, il calcolo effettivo diventa 48+mod(7+sum,11). Aggiungiamo 48 al risultato per riconvertire in un carattere ASCII.

Il carattere di checksum viene aggiunto alla fine del risultato e il valore restituito.


5

Gelatina , 12 byte

ṫ4ṖȮV€xJS%11

Questo è un programma completo che utilizza stringhe per l'I / O.

Provalo online!

Come funziona

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

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

-3 byte grazie al suggerimento di @ Shaggy .



1
O forse anche 56 byte .
Shaggy,

Quindi perché non inserire una matrice di cifre? 54 byte
tsh


3

Pyth , 16 byte

%s.e*ksbpP>Q3hT

Provalo qui!

Pyth , 17 byte

%s*VsMKpP>Q3SlK11

Provalo qui!

Spiegazione

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

Ci siamo venuti in fondo al pub l'altra sera e me ne sono dimenticato tutto.

s3J
U+¬x_*°TÃuB

Provalo


Pensa di poter salvare un byte con s3JeU+¬x_*°TÃuB
ETHproductions

Strano; avrei giurato di averlo provato. Grazie, @ETHproductions.
Shaggy,

Aspetta, no, avevo dimenticato il U... D'oh!
Shaggy,

3

Esagonia , 77 61 byte

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

Provalo online!


Colorato:


Ecco una versione più grande. Ci sono alcuni incroci di percorso, ma poiché tutte quelle celle sono .(no-op in Hexagony), non devi preoccuparti di loro:

(Ho anche provato a mantenere i vecchi specchi, ma a volte ho bisogno di cambiare qualcosa)

Il comando lineare eseguito è:

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

Spiegazione: Invece di mantenere un contatore e moltiplicare per ogni cifra, questo programma:

  • mantenere una variabile "somma parziale" e variabile "somma totale" ( pe t)
  • per ogni cifra letta: aggiungila alla somma parziale e aggiungi la somma parziale alla somma totale.
  • stampa (-p-t)%11, dove %restituiscono sempre risultati positivi.

3

K (oK) , 29 25 24 23 byte

Soluzione:

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

Provalo online!

Esempi:

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"

Spiegazione:

La valutazione viene eseguita da destra a sinistra.

Due trucchi presi da altre soluzioni:

  • moltiplicare per 1 2 3 ... invece di 10 9 8 ...
  • moltiplicare i valori ASCII e quindi aggiungere 7 alla somma per bilanciare

Abbattersi:

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

Gli appunti:

  • -4 byte grazie a Martin Enders di " appena invertito i coefficienti " magia.
  • -1 byte grazie a Tom Carpenter per aver rimosso la necessità di convertire in numeri interi (aggiungendo 7alla somma)
  • -1 byte avvia l'accumulatore da 7

3

C (gcc), 96 95 87 86 85 byte

(-1 grazie 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;}

Provalo online!

Per essere chiamato come f(s), dov'è sun puntatore al primo elemento di un array di caratteri modificabile. Modifica l'array di input, restituisce un puntatore all'array di input.




2

ECMAScript 6 , 86 67 byte

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

Provalo online!


Grazie per il commento di Arnauld , passati dal reduceal mape si sono sbarazzati di returnparola chiave.


3
Benvenuti in PPCG! Le risposte devono essere programmi completi o funzioni richiamabili (sebbene possano essere funzioni senza nome), non solo snippet. Credo che l'opzione più breve in JavaScript sia in genere un lambda senza nome.
Martin Ender,

@MartinEnder grazie, ho modificato la mia risposta
Kos,

3
Benvenuto a bordo! Alcuni consigli: l'inizializzazione delle variabili può essere generalmente utilizzata come parametro aggiuntivo di map(), reduce()ecc. Con qualche riscrittura aggiuntiva, è spesso possibile eliminare {}e return. Inoltre, in questo caso particolare, map()è probabilmente più breve di reduce(). ( Ecco una versione a 65 byte.)
Arnauld

Sono abbastanza sicuro che f=non sia necessario. Inoltre, puoi inizializzare callo spread per qualcosa del genere: a=>{i=10;s=[...c=a.substr(3,9)].reduce((g,v)=>+g+(i--)*v,0)%11;return c+=s?11-s:0}(-4 byte)
Asone Tuhid

2

Retina 0.8.2 , 72 51 byte

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

¶(1*)
$.1

Provalo online! Perché non ho ancora imparato Retina 1.0. Spiegazione:

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

Elimina i caratteri indesiderati e crea una seconda copia delle cifre appropriate.

r`.\G
$&$'

Suffissa ogni cifra nella seconda copia con il suo suffisso. Ciò ripete efficacemente ogni cifra nel suffisso per la sua posizione.

r`.\G
$*

Converti le cifre nella seconda copia in unarie aggiungendole così insieme.

1{11}

Riduci modulo 11. (Nella prima copia ci sono solo 9 cifre, quindi questo non può mai influire su di esso.)

¶(1*)
$.1

Convertire il risultato in decimale e rimuovere nuovamente la nuova riga.


2

APL (Dyalog Unicode) , 26 24 byte

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

Provalo online!

Funzione prefisso tacita. Accetta l'input come stringa.

2 byte salvati grazie a @ngn.

Come?

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

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

Abbellire

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

Test

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 byte

Sfortunatamente, in PHP (-$c)%11è lo stesso di -($c%11); quindi devo ottenere la differenza almeno per la somma più grande possibile (55 * 9 = 495 = 45 * 11) invece di usare semplicemente -$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;

Esegui come pipe -nRo provali online .


0

Java 10, 110 byte

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

Accetta input e output come longnumero intero. Provalo online qui .

Versione non golfata:

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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.