ISBN-13からISBN-10への変換


21

前書き

この課題では、ISBN-13コードが存在する場合、ISBN-13コードを指定して書籍のISBN-10コードを生成することがタスクです。このようなISBN-13コードは、以下で区切られたいくつかの部分で構成されてい-ます。

978-GG-PPPP-TTT-C

文字G(グループ)、P(発行者)、T(タイトル)、およびC(チェックサム)はすべて1桁を表します。このチャレンジの目的では、グループ化と計算Cこのチャレンジを参照)はおもしろくありません。このタスクを簡単にするために、すべてのハイフンを削除します。

ISBN-10番号のレイアウトは非常に似ています。

GG-PPPP-TTT-c

文字GPおよびTは、13桁のISBNと同じcですが、異なります(異なるアルゴリズムを使用して計算されます)。数字cは、次の等価性が保持されるように選択されます(数字が順番に並んでいます)。

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

ISBN番号について考えてみましょう。9780345391803対応するISBN-10コードを取得するには、先頭978のチェックサムとチェックサムが3降っているだけ034539180です。

次に、新しいチェックサムを計算する必要があります。

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

で割り切れる次の番号11はです187。そのため、新しいチェックサムは2ISBN-10コードになります0345391802

ルール

  • 入力には常に対応するISBN-10番号が付けられます(つまり、正確に13桁で始まり、で始まります978
  • 入力は、必ずしも有効なISBN-13である必要はありません(例:。 9780000000002
  • 結果のISBNが次で終わらないことが保証されます X
  • 入力は整数または文字列(ハイフンの有無にかかわらず)として取得できますが、事前に計算された数字のリストは許可されていません
  • 出力は有効なISBN-10番号である必要があります(ハイフンの有無にかかわらず)
  • 出力は整数または文字列である可能性があります(ここでも数字のリストはありません)

テストケース

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

先行ゼロに注意してください!


5
ソリューションにはまったく影響しませんが、That Guyであるためだけに、ISBNの部分(-10または-13のいずれか)がどのように分離されるかについての説明は間違っています。登録グループ要素は可変長であり、後続の部分の桁数は登録グループ間および登録グループ内で異なる場合があります。例えば、双方に0-684-84328-5及び99921-58-10-7、最初の部分が(0および99921それぞれ)は、第2の部分は、パブリッシャである、というように、登録基です。
ヨルダン

5
10/10サンプルISBNの選択
ヤコブ

回答:


10

網膜 44  39 28バイト

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

_

オンラインでお試しください!

説明

いくつかの新しいRetina機能を披露します。:)

>,L3,-2`.+

入力全体をと一致させ、.+その一致を返しますが、L3(ゼロベース)から-2(最後から2番目)までの文字のみを選択します。また、末尾の改行なしで結果を出力し>ます()。

今、Retinaで物事を差し引くのは少し面倒です。しかし、幸いなことに、11を法として作業しているので、線形結合(mod 11)の係数を反転し、すべてを加算できます。つまり、制約が次の場合:

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

次に取得します:

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

ここでは、物事が大幅に簡素化されます。

.
$.>`**

各文字を下部のその文字に置き換えます。*Retinaの繰り返し演算子です。これは右結合型であり$&、左と_右に暗黙のオペランドがあるため、実際の置換はの略です$.>`*$&*_dアンダースコアの$&*_文字列を作成します。dは現在置き換えている数字です。次に、一致までの文字列の長さです。1したがって、式全体は、線形結合のn番目の項の単項表現になります。$.>`

_{11}

実際のモジュロの実行は単項式では簡単です。11個のアンダースコアの完全なセットをすべて削除するだけです。

_

最後に、アンダースコアの数を数えて結果を出力し、ISBN-10を完成させます。


1$.>`マッチまでの文字列の長さはどのように与えますか?$`正規表現の置換に慣れている場合があります。これにより、一致するまで(ただし除外する)文字列が得られます。挿入することによって>、我々はコンテキストをシフトすることができる$`セパレータ(現在の桁と次との間の空の文字列である)現在のマッチと次との間。その区切り$`には現在の一致が含まれます。だから、$>`書くための短い方法です$`$&。最後に、すべてのための$x型の置換元素、網膜は、あなたが挿入できます.後に$その長さを取得します。


このモジュロ11マジックとは?!それは私に4バイトを節約します...しかし、私は得ません!
ストリートスター

1
@streetster基本的に、-2 ≡ 9 (mod 11)(数値に11を加算または減算しても、合同クラスmod 11の「値」は変更されないため)。また、加算と乗算は合同クラスを尊重するため、線形結合の任意の値を現在のモジュロの下で同等の値に置き換えることができます。負の数について話しているのは、実際にはc、一方の側に方程式を再配置し、もう一方の側に他のすべての項(負として)を再配置したためです。
マーティンエンダー

今それを手に入れたと思う。あなたが動くようcになることを超える-c = ...とむしろ乗じよりも、10 9 8...あなた引く11取得するためにそれぞれから-1 -2 -3...その後、乗算、すべてをしてによって-1取得しますc
ストリートスター

最後の段階が最後のアンダースコアだけを置き換える理由を説明していただけますか?何が原因であるのかを理解しようとしてしばらく費やしましたが、再現できないようです。ちなみに、この更新プログラムはすばらしく見えます。
FryAmTheEggman

1
@FryAmTheEggman Thanks :)その時点では、文字列にはアンダースコアのみが含まれています。最初の段階ですでに最初の9桁を印刷しました。
マーティンエンダー


5

PowerShell96 84バイト

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

オンラインでお試しください!

入力を受け取り、適切な部分のみを取得"$args"する正規表現-replaceを実行し、それを$x文字列として保存します。次に、それをchar-array としてキャストし、各文字をループします。ループ内で、事前にデクリメント$a(デフォルトは0)し、チェックサム計算に従って乗算します。へのキャストに注意してくださいint。そうでない場合、ASCII値が使用されます。

次に、-joinそれらの数値を一緒に+パイプし、それをパイプしますiexInvoke-Expressionに似ていますeval)。それを取り、%11そのチェックサムをに格納します$y。最後に、concatenateを文字列化$x + $yし、パイプラインに残します。出力は暗黙的です。

Emignaのおかげで12バイト節約されました。


私は本当にpowershellを知りませんが、このような何かが
84-エミグナ

@Emignaはい、もちろん。モジュラス演算と私の脳はうまく動作しません。
AdmBorkBork

5

オクターブ46 41 39 37バイト

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

オンラインでお試しください!

コードは文字列として入力を受け取り、文字列を返します。

コードは次のように分類されます。

@(a) 無名関数を作成します。

[c=a(4:12) ... ]私たちは、メインコードを形成する文字を抽出するためにコピーを保存しc、後で使用するため、最終的な出力文字列に別のコピーを追加します。

にスワップ10:-1:2する@MartinEnterの巧妙な方法に基づいて1:10、その範囲を簡単に生成し、転置して列ベクトルを取得できます。c*(1:10)'行ベクトルcと範囲列ベクトルの配列乗算を行います。これは、要素ごとの乗算を行ってから加算することと同じです。

通常、チェックサムはmod(11-sum,11)合計が11の倍数になるために必要な数を計算します。ただし、c文字列であるため、実際には数を掛けたために合計が2592(48 * 54)より大きいはずです。実際の値よりも48大きくなりました。

モジュロを実行すると、その2592のうち7つを除くすべてが自動的に削除されます。したがって、範囲の否定を考慮して、実際の計算はになり48+mod(7+sum,11)ます。結果に48を追加して、ASCII文字に変換します。

チェックサム文字が結果の最後に追加され、値が返されます。


5

ゼリー、12バイト

ṫ4ṖȮV€xJS%11

これは、I / Oに文字列を使用する完全なプログラムです。

オンラインでお試しください!

使い方

ṫ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バイト

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

@Shaggyの提案のおかげで-3バイト。



1
または多分56バイト
シャギー

では、なぜ数字の配列として入力しないのですか?54バイト
-tsh


3

Pyth、16バイト

%s.e*ksbpP>Q3hT

ここで試してみてください!

Pyth、17バイト

%s*VsMKpP>Q3SlK11

ここで試してみてください!

説明

%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

Japt16 15バイト

他の夜にパブでこれを見つけて、それをすべて忘れました。

s3J
U+¬x_*°TÃuB

それを試してみてください


あなたがバイトを保存することができると思うs3JU+¬x_*°TÃuB
ETHproductions

奇妙な; 私はそれを試したと誓ったかもしれない。ありがとう、@ ETHproductions。
シャギー

待って、いや、忘れてしまったU-ドー!
シャギー

3

六角形77 61バイト

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

オンラインでお試しください!


色付き:


ここに拡大版があります。いくつかのパスの交差点がありますが、これらのセルはすべて.(Hexagonyではノーオペレーション)であるため、それらについて心配する必要はありません。

(古いミラーも保持しようとしましたが、時々変更する必要があります)

実行される線形コマンドは次のとおりです。

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

説明:このプログラムは、カウンターを保持して各桁で乗算を行う代わりに、次のことを行います。

  • 「部分合計」変数と「合計合計」変数を保持する(pおよびt
  • 読み取られた各桁に対して、それを部分合計に追加し、部分合計を合計に追加します。
  • print (-p-t)%11%常に肯定的な結果を返します。

3

K(oK)29 25 24 23バイト

溶液:

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

オンラインでお試しください!

例:

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"

説明:

評価は右から左に実行されます。

他のソリューションから取った2つのトリック:

  • 10 9 8の代わりに1 2 3 ...を掛けます
  • ASCII値を乗算し、合計に7を加算してバランスを取ります

壊す:

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

ノート:

  • マーティン・エンダースのちょうど逆の係数」魔法おかげで-4バイト
  • 整数への変換の必要性を除去してくれたTom Carpenterに-1バイトを感謝(7合計に加算)
  • -1バイトは7でアキュムレーターを開始します

3

C(gcc)、 96 95 87 86 85バイト

(ceilingcatのおかげで-1)

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

オンラインでお試しください!

として呼び出されるf(s)場合、sは、変更可能な文字配列の最初の要素へのポインターです。入力配列を変更し、入力配列へのポインターを返します。




2

ECMAScriptの686の 67バイト

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

オンラインでお試しください!


おかげでアルノーさんのコメントが、切り替えreducemapし、処分したreturnキーワード。


3
PPCGへようこそ!回答は、スニペットだけでなく、完全なプログラムまたは呼び出し可能な関数(名前のない関数である場合もあります)でなければなりません。JavaScriptの最も短いオプションは通常、名前のないラムダだと思います。
マーティンエンダー

@MartinEnderありがとう、回答を編集しました
コス

3
ご乗車(搭乗)ありがとうございます!いくつかのヒント:変数の初期化は通常map()reduce()などの追加のパラメーターとして配置できます。いくつかの追加の書き換えを行うことで{}、およびを取り除くことができreturnます。また、この特定のケースでmap()は、はおそらくよりも短いですreduce()。(ここでは 65バイト版です。)
アルノー

f=必要ではないと確信しています。また、次のcようにスプレッドで初期化できます:a=>{i=10;s=[...c=a.substr(3,9)].reduce((g,v)=>+g+(i--)*v,0)%11;return c+=s?11-s:0}
-Asone Tuhid

2

網膜0.8.272の 51バイト

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

¶(1*)
$.1

オンラインでお試しください!Retina 1.0をまだ学んでいないからです。説明:

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

不要な文字を削除し、適切な数字の2つ目のコピーを作成します。

r`.\G
$&$'

2番目のコピーの各数字にサフィックスを付けます。これにより、サフィックスの各桁がその位置によって効果的に繰り返されます。

r`.\G
$*

2番目のコピーの数字を単項に変換し、それらを加算します。

1{11}

モジュロ11を減らします(最初のコピーには9桁しかないため、これに影響することはありません)。

¶(1*)
$.1

結果を10進数に変換し、再度改行を削除します。


2

APL(Dyalog Unicode)26 24バイト

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

オンラインでお試しください!

暗黙のプレフィックス機能。入力を文字列として受け取ります。

@ngnのおかげで2バイト節約されました。

どうやって?

∊⍕¨(⊢,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バイト

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

美化

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

テスト

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バイト

残念ながら、PHP (-$c)%11では、と同じ-($c%11)です。ですから、を使用するだけでなく、少なくとも可能な最大値(55 * 9 = 495 = 45 * 11)までの差を取得する必要があります-$c%11

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

または

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

パイプとして実行する-nR、オンラインで試してください


0

Java 10、110バイト

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

入力と出力をlong整数として受け取ります。オンラインで試すこちらでお

ゴルフされていないバージョン:

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
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.