Mengonversi ISBN-13 ke ISBN-10


21

pengantar

Dalam tantangan ini, tugas Anda adalah membuat kode ISBN-10 untuk buku-buku yang diberi kode ISBN-13-nya, dengan asumsi kode tersebut ada. Kode ISBN-13 tersebut terdiri dari beberapa bagian yang dipisahkan oleh -:

978-GG-PPPP-TTT-C

Huruf G(grup), P(penerbit), T(judul) dan C(checksum) semuanya merupakan satu digit. Untuk tujuan tantangan ini pengelompokan dan perhitungan C(lihat tantangan ini ) tidak menarik dan kami akan membatalkan semua tanda hubung untuk membuat tugas ini lebih sederhana.

Nomor ISBN-10 memiliki tata letak yang sangat mirip:

GG-PPPP-TTT-c

Huruf-hurufnya G, Pdan Tsama dengan ISBN 13 digit, namun cberbeda (dan dihitung menggunakan algoritma yang berbeda). Digit cdipilih sedemikian rupa sehingga kesetaraan berikut berlaku (angka berurutan):

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

Contoh

Mari kita pertimbangkan nomor ISBN 9780345391803: Untuk mendapatkan kode ISBN-10 yang sesuai, kita cukup meninggalkan yang terdepan 978dan 3menghasilkan checksum 034539180.

Selanjutnya kita perlu menghitung checksum baru:

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

Angka berikutnya yang dapat dibagi 11adalah 187, sehingga checksum baru adalah 2dan dengan demikian menghasilkan kode ISBN-10 0345391802.

Aturan

  • Input Anda akan selalu memiliki nomor ISBN-10 yang sesuai (mis. Panjangnya persis 13 digit dan dimulai dengan 978)
  • Input tidak harus harus berupa ISBN-13 yang valid (mis. 9780000000002)
  • Anda dijamin bahwa ISBN yang dihasilkan tidak akan berakhir dengan X
  • Anda dapat mengambil input sebagai integer atau string (dengan atau tanpa tanda hubung) namun daftar digit yang dihitung sebelumnya tidak diizinkan
  • Output Anda harus nomor ISBN-10 yang valid (dengan atau tanpa tanda hubung)
  • Output Anda mungkin bilangan bulat atau string (sekali lagi tidak ada daftar digit)

Testcases

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

Perhatikan nol terkemuka!


5
Sama sekali tidak memengaruhi solusi, tetapi hanya demi menjadi Guy Itu, deskripsi Anda tentang bagaimana bagian-bagian dari ISBN (baik -10 atau -13) dipisahkan tidak benar. Elemen grup registrasi adalah panjang variabel, dan jumlah digit untuk bagian-bagian selanjutnya dapat bervariasi antara, dan di dalam, grup registrasi. Sebagai contoh, di keduanya 0-684-84328-5dan 99921-58-10-7, bagian pertama ( 0dan 99921masing - masing) adalah grup pendaftaran, bagian kedua adalah penerbit, dan sebagainya.
Jordan

5
Sampel ISBN pilihan 10/10
Jakob

Jawaban:


10

Retina ,  44  39 28 byte

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

_

Cobalah online!

Penjelasan

Saatnya memamerkan beberapa fitur Retina baru. :)

>,L3,-2`.+

Kami mencocokkan seluruh input dengan .+, mengembalikan kecocokan itu L, tetapi hanya memilih karakter 3 (berbasis nol) hingga -2 (kedua dari belakang), inklusif. Kami juga mencetak hasilnya tanpa linefeed tambahan ( >).

Sekarang, mengurangi hal-hal di Retina agak menyebalkan. Tapi untungnya, kita sedang bekerja modulo 11, jadi kita bisa membalikkan koefisien kombinasi linear (mod 11) dan menambahkan semuanya. Dengan kata lain, jika batasannya adalah:

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

lalu kita dapatkan:

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

Itu menyederhanakan banyak hal di sini:

.
$.>`**

Kami mengganti setiap karakter dengan hal di bagian bawah. *adalah operator pengulangan Retina. Ini asosiatif-kanan dan memiliki operan implisit $&di sebelah kiri dan _di kanan, sehingga substitusi sebenarnya adalah kependekan $.>`*$&*_. $&*_menciptakan string garis bawah d , di mana d adalah digit yang saat ini kami gantikan. Kemudian $.>`adalah panjang string hingga dan termasuk kecocokan. 1 Oleh karena itu, seluruh ekspresi menghasilkan representasi unary dari n istilah ke- dari kombinasi linier kami.

_{11}

Melakukan modulo yang sebenarnya adalah sepele di unary: kami hanya membuang semua set lengkap 11 garis bawah.

_

Akhirnya, kami menghitung berapa banyak garis bawah yang tersisa dan mencetak hasilnya, yang melengkapi ISBN-10.


1 Bagaimana cara $.>`memberikan panjang string hingga dan termasuk kecocokan? Anda mungkin terbiasa dengan $`substitusi regex, yang memberi Anda string hingga (tetapi tidak termasuk) pertandingan. Dengan menyisipkan >, kita bisa menggeser konteks $`ke pemisah antara pertandingan saat ini dan berikutnya (yang merupakan string kosong antara digit saat ini dan berikutnya). Pemisah itu $`akan mencakup pertandingan saat ini. Begitu $>`juga cara menulis yang lebih pendek $`$&. Akhirnya, untuk semua $xelemen subtitusi semua jenis, Retina memungkinkan Anda memasukkan .setelah $untuk mendapatkan panjangnya.


Apa sihir modulo 11 ini ?! Itu akan menyelamatkan saya 4 byte ... tapi saya tidak mengerti!
streetster

1
@streetster Pada dasarnya, -2 ≡ 9 (mod 11)(karena menambah atau mengurangi angka 11 dari angka tidak mengubah "nilainya" di kelas congruence mod 11). Dan penambahan dan multiplikasi menghormati kelas kongruensi, sehingga Anda dapat mengganti nilai apa pun dalam kombinasi linear dengan nilai setara di bawah modulo saat ini. Alasan saya berbicara tentang angka negatif adalah karena saya telah mengatur ulang persamaan yang ada cdi satu sisi dan semua istilah lain (sebagai negatif) di sisi lain.
Martin Ender

Saya rasa saya mengerti sekarang. Jadi, Anda beralih cmenjadi -c = ...dan bukannya mengalikannya dengan 10 9 8...mengurangi 11dari masing-masing untuk mendapatkan -1 -2 -3...dan kemudian mengalikan semuanya dengan -1 untuk mendapatkan c.
streetster

Maukah Anda menjelaskan mengapa tahap akhir hanya mengganti garis bawah trailing? Saya telah menghabiskan waktu mencoba untuk mencari tahu apa yang menyebabkannya, tetapi saya sepertinya tidak bisa mereproduksinya. Pembaruan ini terlihat luar biasa, pekerjaan bagus!
FryAmTheEggman

1
@FryAmTheEggman Terima kasih :) Pada saat itu, string hanya berisi garis bawah. Kami sudah mencetak sembilan digit pertama di tahap pertama.
Martin Ender

6

05AB1E , 17 15 13 12 byte

¦¦¦¨DSƶO11%«

Cobalah online!

Penjelasan

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

Cobalah online!

Mengambil input "$args", melakukan regex -replaceuntuk mendapatkan hanya bagian yang bersangkutan, menyimpannya menjadi $xstring. Lalu kami memberikannya sebagai char-array dan loop melalui setiap huruf. Di dalam loop, kami melakukan pra-pengurangan $a(yang default-nya 0) dan berkembang biak sesuai dengan perhitungan checksum. Perhatikan gips untuk int, kalau tidak ini akan menggunakan nilai ASCII.

Kami kemudian -joinangka-angka itu bersama-sama dengan +dan pipa itu ke iex( Invoke-Expressiondan mirip dengan eval). Kami menerima %11dan menyimpan checksum itu $y. Akhirnya, kami merangkai string $x + $y, dan meninggalkannya di saluran pipa. Output tersirat.

Disimpan 12 byte berkat Emigna.


Saya tidak benar-benar tahu PowerShell, tapi saya pikir sesuatu seperti ini dapat bekerja untuk 84
Emigna

@ Emigna Ya, tentu saja. Aritmatika modulus dan otak saya tidak bermain dengan baik.
AdmBorkBork

5

Oktaf , 46 41 39 37 byte

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

Cobalah online!

Kode mengambil input sebagai string, dan mengembalikan string.

Kode rusak sebagai berikut:

@(a) menciptakan fungsi anonim.

Dengan [c=a(4:12) ... ]kami mengekstrak karakter yang membentuk kode utama, menyimpan salinanc untuk digunakan nanti, dan menambahkan salinan lain ke string hasil akhir.

Berdasarkan @ cara cerdas MartinEnter ini swapping 10:-1:2ke 1:10, kita dapat dengan mudah menghasilkan berbagai itu dan memindahkannya untuk mendapatkan vektor kolom. c*(1:10)'melakukan perkalian array dari vektor baris cdan vektor rentang kolom. Ini setara dengan melakukan perkalian elemen-bijaksana kemudian menjumlahkan.

Checksum biasanya akan mod(11-sum,11)menghitung jumlah yang diperlukan untuk jumlah menjadi kelipatan 11. Namun, karena ckarakter string, jumlah sebenarnya akan lebih besar daripada yang seharusnya pada 2592 (48 * 54) karena kami dikalikan dengan angka yang 48 lebih besar dari nilai sebenarnya.

Ketika kita melakukan modulo, modulo itu akan secara otomatis menghilangkan semua kecuali 7 dari 2592 itu. Dengan demikian, dan memperhitungkan negasi dari rentang, perhitungan aktual menjadi 48+mod(7+sum,11). Kami menambahkan pada 48 hasil untuk mengkonversi kembali ke karakter ASCII.

Karakter checksum ditambahkan ke akhir hasil, dan nilai dikembalikan.


5

Jelly , 12 byte

ṫ4ṖȮV€xJS%11

Ini adalah program lengkap yang menggunakan string untuk I / O.

Cobalah online!

Bagaimana itu bekerja

ṫ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 terima kasih atas saran @ Shaggy .



1
Atau mungkin bahkan 56 byte .
Shaggy

Jadi mengapa tidak dimasukkan sebagai array angka? 54 byte
tsh


3

Pyth , 16 byte

%s.e*ksbpP>Q3hT

Coba di sini!

Pyth , 17 byte

%s*VsMKpP>Q3SlK11

Coba di sini!

Penjelasan

%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

Datang dengan ini di pub malam itu dan lupa semua tentang itu.

s3J
U+¬x_*°TÃuB

Cobalah


Pikirkan Anda dapat menyimpan byte dengan s3JdanU+¬x_*°TÃuB
ETHproduksi

Aneh; bisa bersumpah aku sudah mencobanya. Terima kasih, @ETHproductions.
Shaggy

Tunggu, tidak, aku sudah lupa U- D'oh!
Shaggy

3

Hexagony , 77 61 byte

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

Cobalah online!


Berwarna:


Ini adalah versi yang lebih besar. Ada beberapa jalur penyeberangan, tetapi karena semua sel itu .(tidak ada dalam Hexagony), Anda tidak perlu khawatir tentang mereka:

(Saya juga mencoba menyimpan cermin lama, tetapi kadang-kadang saya perlu mengubah sesuatu)

Perintah linear yang dijalankan adalah:

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

Penjelasan: Alih-alih menjaga penghitung dan melakukan penggandaan di setiap digit, program ini:

  • pertahankan variabel "jumlah parsial" dan variabel "jumlah total" ( pdan t)
  • untuk setiap digit baca: tambahkan ke jumlah parsial, dan tambahkan jumlah parsial ke jumlah total.
  • cetak (-p-t)%11, di mana %selalu mengembalikan hasil positif.

3

K (oK) , 29 25 24 23 byte

Larutan:

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

Cobalah online!

Contoh:

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"

Penjelasan:

Evaluasi dilakukan dari kanan ke kiri.

Dua trik diambil dari solusi lain:

  • kalikan dengan 1 2 3 ... bukannya 10 9 8 ...
  • gandakan nilai ASCII dan kemudian tambahkan 7 ke jumlah untuk menyeimbangkan

Kerusakan:

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

Catatan:

  • -4 bytes terima kasih kepada Martin Enders " hanya membalikkan koefisien sihir ".
  • -1 byte terima kasih kepada Tom Carpenter karena telah menghapus kebutuhan untuk mengkonversi ke integer (dengan menambahkan 7jumlahnya)
  • -1 byte mulai akumulator pada 7

3

C (gcc), 96 95 87 86 85 byte

(-1 terima kasih kepada 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;}

Cobalah online!

Untuk disebut sebagai f(s), di mana sadalah penunjuk ke elemen pertama dari array karakter yang dapat dimodifikasi. Memodifikasi array input, mengembalikan pointer ke array 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)

Cobalah online!


Terima kasih untuk komentar Arnauld ini , beralih dari reduceke mapdan menyingkirkan returnkata kunci.


3
Selamat datang di PPCG! Jawaban harus berupa program lengkap atau fungsi yang dapat dipanggil (meskipun mungkin bukan fungsi yang disebutkan namanya), bukan hanya cuplikan. Saya percaya opsi terpendek dalam JavaScript biasanya lambda yang tidak disebutkan namanya.
Martin Ender

@ MartinEnder terima kasih, saya telah mengedit jawaban saya
Kos

3
Selamat datang! Beberapa tips: Inisialisasi variabel biasanya dapat dimasukkan sebagai parameter tambahan map(), reduce()dll. Dengan beberapa penulisan ulang tambahan, seringkali mungkin untuk menyingkirkan {}dan return. Juga, dalam kasus khusus ini, map()mungkin lebih pendek dari reduce(). ( Ini adalah versi 65-byte.)
Arnauld

Saya cukup yakin f=tidak perlu. Anda juga dapat menginisialisasi cpada spread untuk sesuatu seperti ini: 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 byte

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

¶(1*)
$.1

Cobalah online! Karena saya belum belajar Retina 1.0. Penjelasan:

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

Hapus karakter yang tidak diinginkan dan buat salinan kedua dari angka yang sesuai.

r`.\G
$&$'

Sufiks setiap digit pada salinan kedua dengan sufiksnya. Ini secara efektif mengulangi setiap digit dalam suffix dengan posisinya.

r`.\G
$*

Konversikan digit pada salinan kedua menjadi unary sehingga menambahkannya bersama-sama.

1{11}

Kurangi modulo 11. (Hanya ada 9 digit di salinan pertama, jadi ini tidak akan pernah mempengaruhinya.)

¶(1*)
$.1

Ubah hasilnya kembali menjadi desimal dan hapus baris baru lagi.


2

APL (Dyalog Unicode) , 26 24 byte

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

Cobalah online!

Fungsi awalan Tacit. Mengambil input sebagai string.

2 byte disimpan berkat @ngn.

Bagaimana?

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

Yg diperindahkan

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

Uji

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

Sayangnya, dalam PHP (-$c)%11sama dengan -($c%11); jadi saya harus mendapatkan perbedaan setidaknya jumlah terbesar yang mungkin (55 * 9 = 495 = 45 * 11) daripada hanya menggunakan -$c%11.

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

atau

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

Jalankan sebagai pipa dengan -nRatau coba 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;}

Mengambil input dan output sebagai longinteger. Cobalah online di sini .

Versi tidak disatukan:

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
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.