ISBN-13’ü ISBN-10’a dönüştürme


21

Giriş

Bu zorlukta göreviniz, böyle bir kodun var olduğunu varsayarak, ISBN-13 kodunu verilen kitaplar için ISBN-10 kodunu oluşturmaktır. Böyle bir ISBN-13 kodu, aşağıdakilerle ayrılmış birkaç bölümden oluşur -:

978-GG-PPPP-TTT-C

G(Grup), P(yayıncı), T(başlık) ve C(sağlama toplamı) harflerinin tümü bir rakam için kullanılır. Bu zorluğun amacı için gruplandırma ve hesaplama C( bu zorluğa bakınız ) ilginç değildir ve bu görevi daha basit hale getirmek için tüm kısa çizgileri bırakacağız.

Bir ISBN-10 numarasının çok benzer bir düzeni vardır:

GG-PPPP-TTT-c

Harfler G, Pve T13 basamak için olanla aynıdır, ISBN, ancak cfarklı (ve farklı bir algoritma kullanılarak hesaplanır). Rakam c, aşağıdaki denkliğin tutacağı bir şekilde seçilir (sırayla rakam):

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

Örnek

ISBN numarasını dikkate alalım 9780345391803: Karşılık gelen ISBN-10 kodunu almak 978için satır 3başını ve sağlama toplamı değerini düşürelim 034539180.

Sonra yeni sağlama toplamını hesaplamamız gerekiyor:

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

Bir sonraki numara bölünebilir 11olan 187yeni bir sağlama toplamı, bu yüzden 2bu şekilde elde edilen ISBN-10 kod ve 0345391802.

kurallar

  • Girişiniz her zaman karşılık gelen ISBN-10 numarasına sahip olacaktır (yani, tam olarak 13 rakam uzunluğunda olan ve ile başlayan 978)
  • Giriş mutlaka geçerli bir ISBN-13 olmak zorunda değildir (örn. 9780000000002)
  • Elde edilen ISBN’nin bitmeyeceğine dair garanti X
  • Girdiyi bir tamsayı veya dize olarak (tire ile veya tire olmadan) alabilirsiniz, ancak önceden hesaplanmış bir rakam listesine izin verilmez.
  • Çıktınız geçerli bir ISBN-10 numarası olmalıdır (tire ile veya tire olmadan)
  • Çıktınız bir tamsayı veya dize olabilir (yine basamak listesi yok)

testcases

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

Baştaki sıfırlara dikkat edin!


5
Çözümleri hiç etkilemiyor, ancak sadece O Çocuk olmak adına, bir ISBN’nin (-10 veya -13) bölümlerinin nasıl ayrıldığına dair açıklamanız yanlış. Kayıt grubu elemanı değişken uzunluktadır ve sonraki bölümlerin basamak sayısı kayıt grupları arasında ve içinde değişebilir. Örneğin, her ikisi de 0-684-84328-5ve 99921-58-10-7birinci parça ( 0ve 99921sırasıyla) ikinci bölümü yayıncı olduğunu ve bu yüzden, kayıt grubudur.
Jordan

5
10/10 örnek ISBN seçenekleri
Jakob

Yanıtlar:


10

Retina ,  44  39 28 bayt

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

_

Çevrimiçi deneyin!

açıklama

Bazı yeni Retina özelliklerini gösterme zamanı. :)

>,L3,-2`.+

Girdilerin tamamı ile eşleşiriz .+, o eşleşmeyi döndürür L, ancak yalnızca 3 (sıfır temelli) ila -2 (penultimate) dahil, karakterleri seçeriz. Sonucu, satır sonları besleme olmadan da basarız ( >).

Şimdi, Retina'daki şeyleri çıkarmak biraz can sıkıcı. Ama neyse ki, biz modulo 11 çalışıyoruz, bu yüzden sadece lineer kombinasyonun (mod 11) katsayılarını tersine çevirebilir ve her şeyi ekleyebiliriz. Başka bir deyişle, eğer kısıtlama:

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

sonra alırız:

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

Bu, burada işleri çok kolaylaştırıyor:

.
$.>`**

Her karakteri, altındaki şeyle değiştiriyoruz. *Retina'nın tekrarlayan operatörüdür. Bu doğru bir ilişkiseldir ve $&solda ve _sağda gizli operandlar vardır , bu yüzden oyuncu değişikliği aslında kısadır $.>`*$&*_. d alt çizgi $&*_dizesini yaratır , burada d şu anda değiştirmekte olduğumuz basamaktır. Daha sonra dizeye kadar olan ve eşleşmeyi içeren uzunluktur. 1. Bu nedenle, bir tekli temsil tüm ifade sonuçları N eden bir doğrusal kombinasyonunun dönem,.$.>`

_{11}

Gerçek modüloun ​​yapılması unary olarak önemsizdir: sadece tüm 11 alt çizgi setini bıraktık.

_

Son olarak, kaç tane alt çizgi kaldığını saydık ve sonucu yazdırdık, bu da ISBN-10'u tamamlıyor.


1 Nasıl yok $.>`etmek ve maçı da dahil olmak üzere yukarı dize uzunluğunu verir? $`Regex ikamelerinde aşina olabilirsiniz , ki bu size dizgiye denk gelir (ama hariç). Bir ekleyerek >, biz bağlamını kayabilir $`için ayırıcı (güncel rakam ve bir sonraki arasındaki boş bir dize) geçerli maçın ve bir sonraki arasında. Bu ayracın $`geçerli eşleşmesini içerecektir. Bu yüzden $>`yazmak için daha kısa bir yoldur $`$&. Son olarak, tüm $xtip ikame elemanları için, Retina uzunluğu almak için bir .sonraki eklemenizi sağlar $.


Bu modulo 11 büyüsü nedir? Bu beni 4 bayt kurtaracak ... ama anlamadım!
streetster

1
@ streetster Temel olarak, -2 ≡ 9 (mod 11)(bir sayıdan 11 eklemek veya çıkarmak , çünkü mod 11 uyum sınıfında "değerini" değiştirmez). Ayrıca toplama ve çarpma eşlik sınıflarına saygı gösterir, böylece lineer bir kombinasyondaki herhangi bir değeri geçerli modulo altındaki eşdeğer bir değerle değiştirebilirsiniz. Olumsuz sayılardan bahsetmemin nedeni c, bir tarafta diğer taraftaki diğer tüm terimleri (negatif olarak) yeniden düzenlememiştim .
Martin Ender

Ben düşünüyorum şimdi anladım. Taşımak Yani colmaya üzerinde -c = ...ve oldukça ile çarpılması daha 10 9 8...size çıkarmak 11için her birinden -1 -2 -3...çarpıyoruz her şey ve tarafından -1 olsun c.
streetster

Nihai aşamanın neden sadece sondaki alt çizgi yerine geçtiğini açıklar mısınız? Buna neyin sebep olduğunu bulmaya çalışırken biraz zaman harcadım, ancak üremiyorum. Bu güncelleme bu arada harika görünüyor!
FryAmTheEggman,

1
@FryAmTheEggman Teşekkürler :) Bu noktada, dize yalnızca alt çizgi içeriyor. İlk aşamada ilk dokuz rakamı zaten bastık.
Martin Ender

6

05AB1E , 17 15 13 12 bayt

¦¦¦¨DSƶO11%«

Çevrimiçi deneyin!

açıklama

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

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

Çevrimiçi deneyin!

Girdiyi alır "$args", -replaceyalnızca ilgili kısmı almak için bir regex yapar, onu bir dizge olarak depolar $x. Sonra onu bir chardizi olarak yazdık ve her harfin içine girdik. Döngü içinde, ön azaltma $a(varsayılan olarak 0) olur ve sağlama toplamı hesaplamasına göre çarpılır. İçin döküm int, aksi takdirde bu ASCII değerlerini kullanır.

Daha sonra -joinbu rakamları birlikte +ve bununla iex( Invoke-Expressionve ona benzer eval) yönlendiriyoruz. Bunu alırız %11ve bu sağlama toplamı deposuna koyarız $y. Sonunda dize bitiştirir $x + $yve onu boru hattında bırakırız. Çıktı kapalı.

Emigna sayesinde 12 bayt kurtarıldı.


Gerçekten powershell bilmiyorum ama böyle bir şey düşünüyorum bu 84 için çalışabilir
Emigna

@Emigna Evet, elbette. Modulus aritmetik ve beynim iyi oynamıyor.
AdmBorkBork

5

Octave , 46 41 39 37 bayt

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

Çevrimiçi deneyin!

Kod bir dize olarak girdi alır ve bir dize döndürür.

Kod aşağıdaki gibi bozuluyor:

@(a) isimsiz bir işlev yaratır.

İle [c=a(4:12) ... ]biz bir kopyasını kaydetme, ana kod oluşturan karakterleri ayıklamak cdaha sonra kullanılmak üzere ve son çıkış dizesine başka bir kopyasını ekleyerek.

Takas MartinEnter akıllıcaymış yolda @ dayanarak 10:-1:2içine 1:10, biz kolayca aralığını oluşturmak ve bir sütun vektörü almak için devrik olabilir. c*(1:10)'Satır vektörü cve aralık sütunu vektörünün dizi çarpımını yapar . Bu, eleman bazında çarpma işlemine eşdeğerdir ve sonra toplanır.

Sağlama toplamı normalde mod(11-sum,11)toplamın 11'in katı olması için gereken sayıyı hesaplamak olacaktır . Ancak, cbir karakter dizgisi olduğundan, toplam gerçekte 2592 (48 * 54) olması gerekenden daha büyük olacaktır çünkü sayılarla çarptık Bu gerçek değerden 48 daha büyüktü.

Modulo yaptığımızda, bu 2592'den 7'si dışında otomatik olarak kurtulur 48+mod(7+sum,11). Bir ASCII karakterine dönüştürmek için sonuca 48 ekleriz.

Sağlama toplamı karakteri sonucun sonuna eklenir ve değer döndürülür.


5

Jöle , 12 bayt

ṫ4ṖȮV€xJS%11

Bu, G / Ç için dizeleri kullanan tam bir programdır.

Çevrimiçi deneyin!

Nasıl çalışır

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

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

@ Shaggy'nin önerisi sayesinde -3 bayt .



1
Veya belki de 56 bayt .
Shaggy

Öyleyse neden rakam dizisi olarak giriş yapmıyorsunuz? 54 bayt
tsh 12:18


3

Pyth , 16 bayt

%s.e*ksbpP>Q3hT

Burada dene!

Pyth , 17 bayt

%s*VsMKpP>Q3SlK11

Burada dene!

açıklama

%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

Altıgen , 77 61 bayt

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

Çevrimiçi deneyin!


Renkli:


İşte daha büyük bir versiyon. Bazı yol geçişleri var, ancak bu hücrelerin tümü .(Hexagony'de çalışmaz) olduğundan, onlar için endişelenmenize gerek yok:

(Eski aynaları tutmaya da çalıştım, ama bazen bir şeyi değiştirmem gerek)

Yürütülen doğrusal komut:

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

Açıklama: Bu program bir sayaç tutmak ve her basamakta çarpma yapmak yerine, bu program:

  • "kısmi toplam" değişkenini ve "toplam toplam" değişkenini ( pve t) saklayın
  • her basamak için okunur: kısmi toplama ekleyin ve kısmi toplamı toplam toplama ekleyin.
  • yazdırmak (-p-t)%11nerede, %her zaman pozitif sonuçlar döndürebilir.

3

K (OK) , 29 25 24 23 bayt

Çözüm:

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

Çevrimiçi deneyin!

Örnekler:

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"

Açıklama:

Değerlendirme sağdan sola yapılır.

Diğer çözümlerden alınan iki numara:

  • 10 9 8 yerine 1 2 3 ...
  • ASCII değerlerini çarpın ve sonra dengelemek için toplamı 7 ekleyin

Yıkmak:

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

Notlar:

  • Martin Enders'insadece katsayıları ters çevir ” büyüsü sayesinde -4 bayt .
  • Tam sayılara dönüştürme ihtiyacını ortadan kaldırdığı için Tom Carpenter sayesinde -1 bayt ( 7toplamı ekleyerek )
  • -1 bayt , akümülatörü 7'de başlatır.

3

C (gcc), 96 95 87 86 85 bayt

(-1 ceilingcat sayesinde)

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

Çevrimiçi deneyin!

Olarak adlandırılabilir için f(s)burada, sdeğiştirilebilir bir karakter dizisinin ilk elemanı bir işaretçidir. Giriş dizisini değiştirir, giriş dizisine bir işaretçi döndürür.




2

ECMAScript 6 , 86 67 bayt

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

Çevrimiçi deneyin!


İçin teşekkürler Arnauld yorumuyla , anahtarlamalı reduceiçin mapve kurtuldum returnanahtar kelime.


3
PPCG'ye Hoşgeldiniz! Cevaplar yalnızca parçacıklar değil, tam programlar veya çağrılabilir işlevler (adsız işlevler olsa da) olmalıdır. JavaScript’teki en kısa seçeneğin genellikle isimsiz bir lambda olduğuna inanıyorum.
Martin Ender

@MartinEnder, cevabımı düzelttim
Kos

3
Gemiye hoş geldiniz! Bazı ipuçları: Değişken başlatma genellikle ekstra parametreler olarak konabilir map(), reduce()bazı ek yeniden yazılması ile vb, genellikle kurtulmak mümkündür {}ve return. Ayrıca, bu özel durumda, map()muhtemelen daha kısadır reduce(). ( İşte 65 bayt versiyonu.)
Arnauld

Gerekmediğinden eminim f=. Ayrıca, böyle bir cşey için yayılmayı başlatabilirsiniz : a=>{i=10;s=[...c=a.substr(3,9)].reduce((g,v)=>+g+(i--)*v,0)%11;return c+=s?11-s:0}(-4 bayt)
Asone Tuhid

2

Retina 0.8.2 , 72 51 bayt

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

¶(1*)
$.1

Çevrimiçi deneyin! Çünkü henüz Retina 1.0'ı öğrenmedim. Açıklama:

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

İstenmeyen karakterleri silin ve uygun rakamların ikinci bir kopyasını alın.

r`.\G
$&$'

İkinci basamağın her basamağını sonekiyle birlikte ekleyin. Bu, sonekteki her rakamı pozisyonuna göre etkili bir şekilde tekrarlar.

r`.\G
$*

İkinci kopyadaki rakamları unary'e dönüştürerek birleştirin.

1{11}

Modulo 11'i azaltın. (İlk kopyada sadece 9 rakam var, bu yüzden onu asla etkileyemez.)

¶(1*)
$.1

Sonucu tekrar ondalık sayıya dönüştürün ve yeni satırı tekrar kaldırın.


2

APL (Dyalog Unicode) , 26 24 bayt

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

Çevrimiçi deneyin!

Tam önek işlevi. Girdiyi string olarak alır.

@Ngn sayesinde 2 bayt kaydedildi.

Nasıl?

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

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

Beautified

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

Ölçek

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 bayt

Ne yazık ki, PHP'de (-$c)%11aynı -($c%11); bu yüzden farkı sadece kullanmak yerine mümkün olan en büyük toplamla (55 * 9 = 495 = 45 * 11) bulmalıyım -$c%11.

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

veya

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

Pipe ile çalıştırın -nRveya çevrimiçi deneyin .


0

Java 10, 110 bayt

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

Giriş ve çıkışları bir longtamsayı olarak alır. Burada çevrimiçi deneyin .

Ungolfed versiyonu:

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
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.