Convertendo o ISBN-13 em ISBN-10


21

Introdução

Nesse desafio, sua tarefa é gerar o código ISBN-10 para livros, considerando seu código ISBN-13, assumindo que esse código exista. Esse código ISBN-13 consiste em várias partes separadas por -:

978-GG-PPPP-TTT-C

As letras G(grupo), P(editor), T(título) e C(soma de verificação) representam um dígito. Para os propósitos deste desafio, o agrupamento e o cálculo de C(veja este desafio ) não são interessantes, e todos os hífens serão eliminados para simplificar essa tarefa.

Um número do ISBN-10 tem um layout muito semelhante:

GG-PPPP-TTT-c

As letras G, Pe Tsão as mesmas do ISBN de 13 dígitos, no entanto, csão diferentes (e são calculadas usando um algoritmo diferente). O dígito cé escolhido de forma que a seguinte equivalência seja válida (dígitos em ordem):

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

Exemplo

Vamos considerar o número do ISBN 9780345391803: para obter seu código ISBN-10 correspondente, simplesmente eliminamos o líder 978e o 3rendimento da soma de verificação 034539180.

Em seguida, precisamos calcular a nova soma de verificação:

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

O próximo número divisível por 11é 187, portanto, a nova soma de verificação é 2e, portanto, o código ISBN-10 resultante 0345391802.

Regras

  • Sua entrada sempre terá um número ISBN-10 correspondente (ou seja, tem exatamente 13 dígitos e começa com 978)
  • A entrada não precisa necessariamente ser um ISBN-13 válido (por exemplo, 9780000000002)
  • Você tem a garantia de que o ISBN resultante não terminará com X
  • Você pode receber a entrada como um número inteiro ou sequência (com ou sem hífens), no entanto, uma lista pré-computada de dígitos não é permitida
  • Sua saída deve ser um número ISBN-10 válido (com ou sem hífens)
  • Sua saída pode ser um número inteiro ou string (novamente sem listas de dígitos)

Casos de teste

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

Observe os zeros à esquerda!


5
Ele não afeta as soluções, mas apenas por ser esse cara, sua descrição de como as partes de um ISBN (-10 ou -13) são separadas está incorreta. O elemento do grupo de registro é de tamanho variável e o número de dígitos para as partes subseqüentes pode variar entre e dentro dos grupos de registro. Por exemplo, em ambos 0-684-84328-5e 99921-58-10-7, a primeira parte ( 0e 99921respectivamente) é o grupo de registro, a segunda parte é o editor e assim por diante.
Jordan

5
10/10 amostras de opções de ISBN
Jakob

Respostas:


10

Retina ,  44  39 28 bytes

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

_

Experimente online!

Explicação

Hora de mostrar alguns novos recursos da Retina. :)

>,L3,-2`.+

Combinamos toda a entrada com .+, retornamos essa correspondência L, mas selecionamos apenas os caracteres 3 (com base em zero) a -2 (penúltimo), inclusive. Também imprimimos o resultado sem um avanço de linha à direita ( >).

Agora, subtrair coisas na Retina é um pouco chato. Mas, felizmente, estamos trabalhando no módulo 11, para podermos inverter os coeficientes da combinação linear (mod 11) e somar tudo. Em outras palavras, se a restrição for:

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

então temos:

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

Isso simplifica bastante as coisas aqui:

.
$.>`**

Substituímos cada personagem por aquela coisa na parte inferior. *é o operador de repetição da Retina. É associativo à direita e possui operandos implícitos $&à esquerda e _à direita, portanto a substituição é realmente curta $.>`*$&*_. $&*_cria uma sequência de d sublinhados, em que d é o dígito que estamos substituindo no momento. Então $.>`é o comprimento da corda até e incluindo a correspondência. 1 Portanto, toda a expressão resulta em uma representação unária do n ésimo termo da nossa combinação linear.

_{11}

Fazer o módulo real é trivial em unário: nós apenas eliminamos todos os conjuntos completos de 11 sublinhados.

_

Por fim, contamos quantos sublinhados restam e imprimimos o resultado, o que completa o ISBN-10.


1 Como $.>`atribuir o comprimento da corda até e incluindo a correspondência? Você pode estar familiarizado com as $`substituições de expressões regulares, que fornecem a string até (mas excluindo) a correspondência. Ao inserir a >, podemos mudar o contexto de $`para o separador entre a correspondência atual e a próxima (que é uma string vazia entre o dígito atual e o próximo). Esse separador $`incluirá a correspondência atual. Portanto, $>`é uma maneira mais curta de escrever $`$&. Por fim, para $xelementos de substituição de todos os tipos, o Retina permite inserir um .após o $para obter seu comprimento.


O que é essa mágica do módulo 11 ?! Isso me salvará 4 bytes ... mas eu não entendo!
Streetster

1
@streetster Basicamente, -2 ≡ 9 (mod 11)(porque adicionar ou subtrair 11 de um número não altera seu "valor" na classe de congruência mod 11). E adição e multiplicação respeitam classes de congruência, para que você possa substituir qualquer valor em uma combinação linear por um valor equivalente no módulo atual. A razão pela qual estou falando de números negativos é realmente apenas que reorganizei a equação para ter cde um lado e todos os outros termos (como negativos) do outro.
Martin Ender

Eu acho que entendi agora. Então você passa ca se tornar -c = ...e, em vez de multiplicar, 10 9 8...subtrai 11de cada um para obter -1 -2 -3...e multiplica tudo por -1 para obter c.
Streetster

Você se importaria de explicar por que a etapa final substitui apenas os sublinhados à direita? Passei um tempo tentando descobrir o que está causando isso, mas não consigo reproduzi-lo. A propósito, essa atualização parece incrível, bom trabalho!
FryAmTheEggman

1
@FryAmTheEggman Obrigado :) Nesse ponto, a string contém apenas sublinhados. Já imprimimos os nove primeiros dígitos na primeira etapa.
Martin Ender

6

05AB1E , 17 15 13 12 bytes

¦¦¦¨DSƶO11%«

Experimente online!

Explicação

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

Experimente online!

Recebe entrada "$args", executa uma regex -replacepara obter apenas a parte pertinente, armazena-a $xcomo uma sequência. Então, lançamos isso como uma charmatriz e percorremos cada letra. Dentro do loop, pré-decréscimos $a(cujo padrão é 0) e multiplicamos de acordo com o cálculo da soma de verificação. Observe a conversão para int, caso contrário, isso usaria valores ASCII.

Em seguida, -joinesses números juntos +e canalizamos isso paraiex ( Invoke-Expressione semelhante a eval). Pegamos isso %11e armazenamos essa soma de verificação $y. Por fim, concatenamos $x + $ye deixamos isso no pipeline. A saída está implícita.

Economizou 12 bytes graças a Emigna.


Eu realmente não sei PowerShell, mas acho que algo como isso pode funcionar para 84
Emigna

@Emigna Sim, é claro. Módulo aritmético e meu cérebro não funciona muito bem.
AdmBorkBork 19/01

5

Oitava , 46 41 39 37 bytes

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

Experimente online!

O código recebe a entrada como uma sequência e retorna uma sequência.

O código é dividido da seguinte maneira:

@(a) cria uma função anônima.

Com [c=a(4:12) ... ]extraímos os caracteres que formam o código principal, salvando uma cópia emc para uso posterior e adicionando outra cópia à sequência de saída final.

Baseado em @ maneira inteligente de MartinEnter de trocar 10:-1:2para 1:10, podemos facilmente gerar desse intervalo e transpô-la para obter um vector coluna. c*(1:10)'faz a multiplicação de vetor do vetor de linha ce vetor de coluna de intervalo. Isso é equivalente a fazer uma multiplicação por elementos e depois somar.

A soma de verificação normalmente seria mod(11-sum,11)calcular o número necessário para a soma ser um múltiplo de 11. No entanto, como cera uma sequência de caracteres, a soma será realmente maior do que deveria em 2592 (48 * 54), porque multiplicamos por números que eram 48 maiores que o valor real.

Quando executamos o módulo, ele automaticamente se livra de todos, exceto 7, desse 2592. Como tal, e contabilizando a negação do intervalo, o cálculo real se torna 48+mod(7+sum,11). Adicionamos 48 ao resultado para converter novamente em um caractere ASCII.

O caractere de soma de verificação é anexado ao final do resultado e o valor retornado.


5

Gelatina , 12 bytes

ṫ4ṖȮV€xJS%11

Este é um programa completo que usa cadeias de caracteres para E / S.

Experimente online!

Como 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, graças à sugestão de @ Shaggy .



1
Ou talvez até 56 bytes .
Salsicha

Então, por que não inserir como matriz de dígitos? 54 bytes
tsh


3

Pitão , 16 bytes

%s.e*ksbpP>Q3hT

Experimente aqui!

Pitão , 17 bytes

%s*VsMKpP>Q3SlK11

Experimente aqui!

Explicação

%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

Japonês , 16 15 bytes

Veio com isso no pub na outra noite e esqueci tudo.

s3J
U+¬x_*°TÃuB

Tente


Pense que você pode salvar um byte com s3JeU+¬x_*°TÃuB
ETHproductions

Esquisito; poderia jurar que eu tentei isso. Obrigado, @ETHproductions.
Shaggy

Espere, não, eu tinha esquecido o U- D'oh!
Shaggy

3

Hexagonia , 77 61 bytes

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

Experimente online!


Colori:


Aqui está uma versão maior. Existem alguns cruzamentos de caminho, mas porque todas essas células são. (não-op no Hexagony), você não precisa se preocupar com elas:

(Eu também tentei manter os espelhos antigos, mas às vezes preciso mudar alguma coisa)

O comando linear executado é:

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

Explicação: Em vez de manter um contador e multiplicar a cada dígito, este programa:

  • mantenha uma variável "soma parcial" e variável "soma total" ( pet )
  • para cada dígito lido: adicione-o à soma parcial e adicione-o à soma total.
  • imprimir (-p-t)%11, %sempre retornando resultados positivos.

3

K (oK) , 29 25 24 23 bytes

Solução:

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

Experimente online!

Exemplos:

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"

Explicação:

A avaliação é realizada da direita para a esquerda.

Dois truques extraídos de outras soluções:

  • multiplique por 1 2 3 ... em vez de 10 9 8 ...
  • multiplique valores ASCII e adicione 7 à soma para equilibrar

Demolir:

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 graças à mágica " apenas inverta os coeficientes " de Martin Enders .
  • -1 byte, graças a Tom Carpenter por remover a necessidade de converter para números inteiros (adicionando 7à soma)
  • -1 byte inicia o acumulador às 7

3

C (gcc), 96 95 87 86 85 bytes

(-1 graças 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;}

Experimente online!

Para ser chamado como f(s), onde sestá um ponteiro para o primeiro elemento de uma matriz de caracteres modificável. Modifica a matriz de entrada, retorna um ponteiro para a 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)

Experimente online!


Obrigado pelo comentário de Arnauld , mudou de reducepara mape se livrou da returnpalavra-chave.


3
Bem-vindo ao PPCG! As respostas devem ser programas completos ou funções que podem ser chamadas (embora possam ser funções sem nome), não apenas trechos. Acredito que a opção mais curta em JavaScript geralmente é uma lambda sem nome.
Martin Ender

@MartinEnder graças, eu editei a minha resposta
Kos

3
Bem-vindo a bordo! Algumas dicas: inicialização de variáveis geralmente pode ser colocado como parâmetros extras de map(), reduce()etc. Com alguma reescrita adicional, muitas vezes é possível se livrar de {}e return. Além disso, nesse caso em particular, map()é provavelmente menor que reduce(). ( Aqui é uma versão 65-byte.)
Arnauld

Tenho certeza que f=não é necessário. Além disso, você pode inicializar cno spread para algo como isto: 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

Experimente online!Porque eu não aprendi Retina 1.0 ainda. Explicação:

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

Exclua os caracteres indesejados e faça uma segunda cópia dos dígitos apropriados.

r`.\G
$&$'

Sufixe cada dígito na segunda cópia com seu sufixo. Isso efetivamente repete cada dígito no sufixo por sua posição.

r`.\G
$*

Converta os dígitos da segunda cópia em unários, adicionando-os.

1{11}

Reduza o módulo 11. (Existem apenas 9 dígitos na primeira cópia, portanto isso nunca poderá afetá-lo.)

¶(1*)
$.1

Converta o resultado novamente em decimal e remova a nova linha novamente.


2

APL (Dyalog Unicode) , 26 24 bytes

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

Experimente online!

Função de prefixo tácito. Recebe entrada como string.

2 bytes salvos graças a @ngn.

Quão?

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

Embelezado

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

Teste

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

Infelizmente, no PHP (-$c)%11é o mesmo que -($c%11); então eu tenho que obter a diferença para pelo menos a maior soma possível (55 * 9 = 495 = 45 * 11) em vez de apenas usar -$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;

Execute como pipe -nRou experimente-os online .


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 e saídas como um longnúmero inteiro. Experimente online aqui .

Versão não destruída:

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
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.