ISBN-13チェックディジットを計算する


28

ISBN-13コードの最初の12桁が与えられると、適切なチェックディジットを計算して追加することでISBN全体を計算する関数を作成します。

関数の入力は、ISBNの最初の12桁を含む文字列です。その出力は、13桁すべてを含む文字列です。

正式な仕様

完全に正確に12桁の10進数で構成される文字列s(および他の文字を含まない)を指定すると、次のプロパティを持つ文字列tを返す関数を作成します。

  • tは正確に13桁の10進数で構成されます(他の文字は含まれません)。
  • stのプレフィックスです。
  • tの奇数位置(つまり、1番目、3番目、5番目など)のすべての数字の合計と、tの偶数位置(つまり、2番目、4番目、6番目など)のすべての数字の合計の3倍10の倍数。

例/テストケース

入力
978030640615

出力
9780306406157

勝利条件

同様に挑戦、最短回答勝利。


1
入力と出力にはダッシュまたは数字のみが含まれていますか?
sepp2k

1
説明を更新しました。入力と出力は数字のみです
ケビンブラウン

ISBN-13全体を出力することも受け入れられますか?
ラマ氏

6
質問は実際には自己完結型である必要があるため、ここにアルゴリズムの説明を含めると役立ちます。
FlipTack

上記の投稿では、テストの例が貧弱です...最後に10 isbnがあり、そのうちの1つは最後の桁として0を返す必要があります...
RosLuP

回答:


14

Golfscript-25文字

{...+(;2%+{+}*3-~10%`+}:f

プログラム全体のバージョンはわずか19文字です

...+(;2%+{+}*3-~10%

後で分析するためにここに戻って確認してください。一方、私の昔のインスピレーションを受けていない答えをチェックしてください

Golfscript-32文字

luhn数の計算に似ています

{.{2+}%.(;2%{.+}%+{+}*~)10%`+}:f

978030640615の分析

{...}:f this is how you define the function in golfscript
.       store an extra copy of the input string
        '978030640615' '978030640615'
{2+}%   add 2 to each ascii digit, so '0'=>50, I can get away with this instead
        of {15&}% because we are doing mod 10 math on it later
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55]
.       duplicate that list
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [59 57 58 50 53 50 56 54 50 56 51 55]
(;      trim the first element off
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [57 58 50 53 50 56 54 50 56 51 55]
2%      select every second element
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [57 50 50 54 56 55]
{.+}%   double each element by adding to itself
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55] [114 100 100 108 112 110]
+       join the two lists together
        '978030640615' [59 57 58 50 53 50 56 54 50 56 51 55 114 100 100 108 112 110]
{+}*    add up the items in the list
        '978030640615' 1293
~       bitwise not
        '978030640615' -1294
)       add one
        '978030640615' -1293            
10%     mod 10
        '978030640615' 7
`       convert to str
        '978030640615' '7'
+       join the strings
        '9780306406157'

インタープリターを介してコードを実行した後、最初の{3文字と最後の3文字を削除することで、いくつかの文字を(32文字のLuhnベースのソリューションで)保存できると思います。}:f。最初の解決策でも同じことができるのかしら
ロブ

@MikeDtrick、これらの文字はGSが関数を定義する方法です。19文字バージョンは、あなたが提案することを行いますが、質問は「機能」を求めました
ニブラー

わかりました、説明ありがとう。
ロブ

必要はありません:f(はい、当時関数は一般的に名前が付けられていました)。
エリックアウトゴルファー

8

Python-44文字

f=lambda s:s+`-sum(map(int,s+s[1::2]*2))%10`

Python-53文字

def f(s):d=map(int,s);return s+`-sum(d+d[1::2]*2)%10`

私がf( '9780306406159')出力'97803064061598'の代わりに'9780306406157'だと思う
Eelvex

@Eelvex、入力文字列は、常に12桁でなければならない
gnibbler

ああ、どういうわけか '9'が忍び込んで
しまい

7

Haskell-54文字

i s=s++show(sum[-read[c]*m|c<-s|m<-cycle[1,3]]`mod`10)

これには、並列リスト内包のサポートが必要です。これは、GHC(-XParallelListCompフラグ付き)およびHugs(フラグ付き)でサポートされてい-98ます。


そのフラグをカウントに含める必要はありませんか?それに加えて、あなたは置き換えることができます[1,3]によって[9,7]および削除-あなたにバイトを:)保存する
ბიმო

7

APL(27文字)

F←{⍵,⍕10|10-(12⍴1 3)+.×⍎¨⍵}

通訳としてDyalog APLを使用しています。主に右から左へ(関数定義内でF←{ ... })簡単な説明を次に示します。

  • ⍎¨⍵:正しい引数()で指定された各(¨)文字を実行/評価()します。
  • (12⍴1 3)ベクター1 312-elementベクターに再形成()します(ギャップを埋めるために繰り返します)。
  • +.×+.×左引数((12⍴1 3))と右引数(⍎¨⍵)の内積()を取ります。
  • 10-:10から減算します。
  • 10|:で除算し10た後の余りを見つけます。
  • :数値をフォーマットします(つまり、文字表現を指定します)。
  • ⍵,,計算された数字を正しい引数に追加()します。

6

PHP- 86 85 82文字

function c($i){for($a=$s=0;$a<12;)$s+=$i[$a]*($a++%2?3:1);return$i.(10-$s%10)%10;}

再フォーマットと説明:

function c($i){                     // function c, $i is the input

    for($a=$s=0;$a<12;)             // for loop x12 - both $a and $s equal 0
                                    // notice there is no incrementation and
                                    // no curly braces as there is just one
                                    // command to loop through

        $s+=$i[$a]*($a++%2?3:1);    // $s (sum) is being incremented by
                                    // $ath character of $i (auto-casted to
                                    // int) multiplied by 3 or 1, depending
                                    // wheter $a is even or not (%2 results
                                    // either 1 or 0, but 0 == FALSE)
                                    // $a is incremented here, using the
                                    // post-incrementation - which means that
                                    // it is incremented, but AFTER the value
                                    // is returned

    return$i.(10-$s%10)%10;         // returns $i with the check digit
                                    // attached - first it is %'d by 10,
                                    // then the result is subtracted from
                                    // 10 and finally %'d by 10 again (which
                                    // effectively just replaces 10 with 0)
                                    // % has higher priority than -, so there
                                    // are no parentheses around $s%10
}

私がC#の回答で採用したアプローチそのものです。PHPは9文字より効率的です!
ネリウス


5

Haskell、78 71 66文字

i s=s++(show$mod(2-sum(zipWith(*)(cycle[1,3])(map fromEnum s)))10)

5

ルビー-73 65文字

f=->s{s+((2-(s+s.gsub(/.(.)/,'\1')*2).bytes.inject(:+))%10).to_s}

"\\1"-> '\1'
Nemo157

@Nemo、ありがとう、私のルビーは少し錆びています
ニブラー

Ruby 1.9構文を使用しますf=->s{...}。6文字節約します。またs<<(...).to_s、48を追加する代わりに書き込み、を使用しますFixnum#chr
-Hauleth

4

C#(94文字)

string I(string i){int s=0,j=0;for(;j<12;)s+=(i[j]-48)*(j++%2<1?1:3);return i+((10-s%10)%10);}

読みやすくするために改行/空白を使用:

string I(string i) 
{ 
    int s = 0, j = 0;
    for (; j < 12; )
        s += (i[j] - 48) * (j++ % 2 < 1 ? 1 : 3); 
    return i + ((10 - s % 10) % 10); 
}

私の棚の本からいくつかのISBNでテストされたので、私はそれが働いていることを知っています!


4

パイソン- 91、89

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|         |         |         |         |         |         |         |         |         |
 def c(i):return i+`(10-(sum(int(x)*3for x in i[1::2])+sum(int(x)for x in i[::2]))%10)%10`

最初の引数とリスト内包のfor(およびin3番目の)の間のスペースは、パーサー(変数名を使用しない)で分割できる限りオプションです。そこに-2文字。
ニックT

4

Perl、53文字

sub i{$_=shift;s/(.)(.)/$s+=$1+$2*3/ge;$_.(10-$s)%10}

4

C#– 89 77文字

string I(string s){return s+(9992-s.Sum(x=>x-0)-2*s.Where((x,i)=>i%2>0).Sum(x=>x-0))%10;}

読みやすいようにフォーマット:

string I(string s)
{
    return s +
            (9992
            - s.Sum(x => x - 0)
            - 2 * s.Where((x, i) => i%2 > 0).Sum(x => x - 0)
            ) % 10;
}

1つまたは3つを掛けるのではなく、すべてを追加するだけでなく、偶数個の文字をすべてもう一度追加し、2を掛けます。

9992は十分に大きいため、すべてのASCII文字の合計はそれよりも小さく(したがって、10でmodし、結果が正であり、10を2回modする必要がないようにできます)、追加するため0で割り切れませんこれらの余分な2 * 12 * 48(12のASCII数字、1と3の重さ)== 1152をすべて増やすことで、余分な文字を1つ節約できます(48を2回引く代わりに、charからintに変換するためだけに0を引いて、しかし、990の代わりに9992を記述する必要があります)。

しかし、それでも、それほど美しくはありませんが;-)、この昔ながらのソリューションでは80文字になります(ただし、これはほとんどC互換です)。

string T(string i){int s=2,j=0;for(;j<12;)s+=i[j]*(9-j++%2*2);return i+s%10;}

4

J- 55 45 38

f=:3 :'y,":10|10-10|+/(12$1 3)*"."0 y'

例えば

f '978030640615'
9780306406157

古い方法:

f=:,":@(10(10&|@-)(10&|@+/@((12$1 3)*(i.12)&(".@{))))

1
(i.12)(".@{)yに置き換えることができます"."0 y
Jガイ

3

ルビー-80文字

def f s;s+(10-s.bytes.zip([1,3]*6).map{|j,k|(j-48)*k}.inject(:+)%10).to_s[0];end

3

dc、44文字

[d0r[I~3*rI~rsn++lndZ0<x]dsxx+I%Ir-I%rI*+]sI

として呼び出しますlIx。例:

dc -e'[d0r[I~3*rI~rsn++lndZ0<x]dsxx+I%Ir-I%rI*+]sI' -e '978030640615lIxp'


2

D-97文字

auto f(string s){int n;foreach(i,c;s)n+=((i&1)*2+1)*(c-48);return s~cast(char)((10-n%10)%10+48);}

より読みやすいフォーマット:

auto f(string s)
{
    int n;

    foreach(i, c; s)
        n += ((i & 1) * 2 + 1) * (c - 48);

    return s ~ cast(char)((10 - n % 10) % 10 + 48);
}

しかし、Dのキャスト演算子の冗長性により、とてつもなく短いコードを書くのが難しくなります。


2

Java-161文字 :(

int b[]=new int[a.length];
int d=0,n=0,j=1;
for(char c:a.toCharArray())b[d++]=Integer.valueOf(c+"");
for(int i:b)n+=(j++%2==0)?(i*3):(i*1);
return a+(10-(n%10));

この答えは関数ではないため、最初の要件を満たしていません。
ハン

1

Q(44文字)

f:{x,string 10-mod[;10]0+/sum@'2 cut"I"$/:x}

これは実際には間違っていると思う
-skeevey

1

Scala 84

def b(i:String)=i+(10-((i.sliding(2,2).map(_.toInt).map(k=>k/10+k%10*3).sum)%10)%10)

テスト:

val isbn="978030640615"
b(isbn)

結果:

"9780306406157"

1

C、80 79文字

この関数は文字列を所定の位置に変更しますが、問題の要件を満たすために元の文字列ポインタを返します。

s;char*f(char*p){for(s=2;*p;s+=7**p++)s+=9**p++;*p++=48+s%10;*p=0;return p-13;}

説明:0各入力文字から48(数字のASCII値)を引く代わりに、累算器sは10を法として48 + 3 * 48 + 48 + 3 * 48 ... + 48 + 3に等しくなるように初期化されます* 48 = 24 * 48 = 1152このステップ10-sums、加算ではなく減算で累積することで回避できます。ただし、%C のモジュール演算子sは負の場合、有効な結果を提供しないためs-=、乗算器3と1 を使用する代わりに、-3 = 7モジュロ10および-1 = 9モジュロ10にそれぞれ置き換えられます。

テストハーネス:

#include <stdio.h>
#define N 12
int main()
{
     char b[N+2];
     fgets(b, N+1, stdin);
     puts(f(b));
     return 0;
}

1

Groovyの75、66の文字

i={int i;it+(10-it.inject(0){t,c->t+(i++&1?:3)*(c as int)}%10)%10}

つかいます:

String z = "978030640615"
println i(z)

-> 9780306406157

1

APL(25)

{⍵,⍕10-10|+/(⍎¨⍵)×12⍴1,3}

アルゴは10 |で終わる必要があります それ以外の場合は、0の代わりに10を返す可能性があるため
RosLuP


1

パイソン278の 76バイト

lambda n:n+`10-(sum(int(a)+3*int(b)for a,b in zip(n[::2],n[1::2]))%10or 10)`

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

引数として文字列を取ります。

説明:

Pythonスライス表記を使用して、文字列を文字ペアのリストに変換します。( "978030640615"-> [( "9"、 "7")、( "8"、 "0")、( "3"、 "0")、( "6"、 "4")、( "0 "、" 6 ")、(" 1 "、" 5 ")])

そのペアのリストについて、各アイテムを整数に変換し、a + 3bを返します。

すべての結果を合計します。

10を法とする合計、または剰余が0の場合は10を取得します(これにより、最終桁が0ではなく10になるのを防ぎます)。

10から残りを削除して、チェックディジットを取得します。

非推奨のバックティック式を使用して、計算されたチェックディジットを文字列に変換します。

元の数値と計算されたチェックディジットを返します。

編集:

スペースを削除して2バイトを節約しました(Jo Kingに感謝!)。


あなたは前にスペースを削除することができますforし、or
ジョー・キング

978186197371は8と9ではない...私はそれからの数を取得する最後の数字を持っているように私には結果だけで、私は私のAPL溶液中で印刷するリンク
RosLuP

私は私が間違っている数...貼り付けていると思いますすみません
RosLuP

1

APL(Dyalog Unicode)、18 バイトSBCS

引数として文字列を取る匿名の暗黙の接頭辞関数。バブラーのアプローチを使用します。

⊢,∘⍕10|⍎¨+.×9 7⍴⍨≢

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

 引数の長さ(12)

9 7⍴⍨[9,7]その長さに 周期的に変形します

+.× それを伴う次の内積:

⍎¨ `各キャラクターを評価する

10| そのmod-10

,∘⍕ 以下の文字列化を追加します:

 変更されていない引数


1

dc、25バイト

dn[A~9z^8+*rd0<M+]dsMxA%p

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

ここにはすでにDCの回答がありますが、25 <44なので、19バイトは問題ないと思います。これは、zが偶数であるか奇数であるかに応じて、8+9^zいずれか-3または-1mod 10 と同等の事実を使用します。したがってA~、スタック上の数字を数字に分割するために使用しますが、スタックを構築するときに、各数字8+9^zに現在のスタックサイズを掛けます。次に、関数スタックが展開するときにそれらをすべて追加し、最後の数字を出力します。


0

MATLAB-82文字

function c(i)
[i num2str(mod(10-mod(sum(str2num(i(:)).*repmat([1;3],6,1)),10),10))]

0

R、147文字

f=function(v){s=as.numeric(strsplit(v,"")[[1]]);t=0;for(i in 1:12)if(i%%2==0)t=t+s[i]*3 else t=t+s[i];paste(v,(10-(t%%10))%%10,collapse="",sep="")}

使用法:

f("978030640615")
[1] "9780306406157"

0

J、25

,[:":10|0(-+/)"."0*1 3$~#
   f =:、[: ":10 | 0(-+ /)"。 "0 * 1 3 $〜#
   f '978030640615'
9780306406157
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.