ISBN-13 kontrol basamağını hesapla


28

Bir ISBN-13 kodunun ilk 12 rakamı verilen, uygun bir kontrol basamağı hesaplayarak ve ekleyerek tüm ISBN'yi hesaplayan bir fonksiyon yazın .

İşlevinizin girişi, ISBN’nin ilk 12 hanesini içeren bir dizedir. Çıktı 13 basamağın tümünü içeren bir dizedir.

Resmi özellikleri

Tamamen tam olarak 12 ondalık basamaktan oluşan (ve başka bir karakter içermeyen) bir dize s verildiğinde , aşağıdaki özelliklere sahip bir t dizesi döndüren bir işlev yazın :

  • t , tam olarak 13 ondalık basamaktan oluşur (ve başka karakter içermez);
  • s , t'nin önekidir ;
  • t cinsindeki tek basamaklardaki tüm rakamların toplamı (yani birinci, üçüncü, beşinci, vb.), artı t'deki eşit konumlardaki tüm rakamların toplamının üç katı (yani ikinci, dördüncü, altıncı, vb.), 10'dan fazla.

Örnek / test durumu

Giriş
978030640615

Çıktı
9780306406157

Zafer durumu

Bir As meydan, en kısa cevap kazanır.


1
Giriş ve çıkışlarda çizgi mi yoksa yalnızca rakamlar mı var?
sepp2k

1
Açıklama güncellendi, girdi ve çıktı yalnızca rakamlardı
Kevin Brown

Tam ISBN-13'ün çıktısı da kabul edilebilir mi?
Bay Llama

6
Soruların gerçekten kendi içinde yer alması gerektiğine dikkat edin, bu nedenle burada algoritmanın bir tanımını eklemek yararlı olacaktır.
FlipTack

Benim için yukarıdaki yazı örnek testin kötü ... Son 10 isbn olurdu ve bunlardan biri son rakam olarak 0 döndürmek zorunda ...
RosLuP

Yanıtlar:


14

Golfscript - 25 karakter

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

Tüm program sürümü sadece 19 karakterdir.

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

Daha sonra analiz için buraya bakın. Bu arada eski ilhamsız cevabımı kontrol et.

Golfscript - 32 karakter

Luhn sayı hesaplamasına benzer

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

978030640615 için analiz

{...}: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'

Kodu tercüman aracılığıyla çalıştırdıktan sonra, ilk {ve son üç karakterden kurtularak bazı karakterleri (32 karakterli Luhn tabanlı çözümünüzde) kaydedebileceğinizi düşünüyorum ; }:f. Acaba aynı şey ilk çözüm için de yapılabilir mi ...
Rob

@MikeDtrick, bu karakterler GS'nin bir işlevi nasıl tanımladığıdır. 19 karakter versiyonu sizin önerdiğiniz şeyi yapıyor, ancak soru bir "işlev" istedi
gnibbler

Oh tamam, açıklama için teşekkür ederim.
Rob

Buna ihtiyacınız yok :f(evet, fonksiyonların genellikle o zamanlar adlandırıldığını biliyorum).
Outgolfer Erik,

8

Python - 44 karakter

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

Python - 53 karakter

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

Bence f ('9780306406159') '9780306406157' yerine '97803064061598'
çıktısını

@Eelvex, giriş dizgisi her zaman 12 rakam olmalıdır
gnibbler

Ah, bir şekilde '9' gizlice girdi. Üzgünüm ...
Eelvex

7

Haskell - 54 karakter

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

Bu, GHC ( bayrakla birlikte) ve Hugs (bayrakla birlikte) tarafından desteklenen paralel liste anlamalarına destek gerektirir .-XParallelListComp-98


Bu bayrağa sayıma dahil etmenize gerek yok mu? Bunun yanı sıra, yerine [1,3]göre [9,7]ve kaldırmak -size byte :) kaydeder hangi
ბიმო

7

APL (27 karakter)

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

Dyalog APL'yi tercüman olarak kullanıyorum. İşte hızlıca bir açıklama, çoğunlukla sağdan sola (işlev tanımı içinde F←{ ... }):

  • ⍎¨⍵: Doğru argümanda ( ) verilen her ( ¨) karakterini yürütün / değerlendirin ( ).
  • (12⍴1 3): Vektörü 1 3yeniden bir vektörde yeniden şekillendirin ( ) 12(boşlukları doldurmak için tekrarlayın).
  • +.×: +.×Sol argümanının ( (12⍴1 3)) nokta ürününü ( ) ve sağ argümanını ( ⍎¨⍵) alın.
  • 10-: 10'dan çıkar.
  • 10|: Tarafından bölündükten sonra kalanı bulun 10.
  • : Sayıyı biçimlendirin (yani, bir karakter gösterimi verin).
  • ⍵,: ,Hesaplanan basamağımızı doğru argümana ekleyin ( ).

6

PHP - 86 85 82 karakter

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

Yeniden biçimlendirme ve açıklama:

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
}

Tam olarak benim C # cevabında benim yaptığım yaklaşım. PHP ~ 9 karakter daha verimli görünüyor!
Nellius

6

Windows PowerShell, 57

filter i{$_+(990-($_-replace'(.)(.)','+$1+3*$2'|iex))%10}

5

Haskell, 78 71 66 karakter

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

5

Ruby - 73 65 karakter

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

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

@Hayır, teşekkürler, yakutum biraz paslı
gnibbler

Ruby 1.9 sözdizimini kullanın f=->s{...}. 6 karakter tasarruf edin. Ayrıca s<<(...).to_s48 ekleyerek yazıp kullanın Fixnum#chr.
Hauleth,

4

C # (94 karakter)

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

Okunabilirlik için çizgi / boşluklu:

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

Rafımdaki kitaplardan birkaç ISBN’te test edilmiştir, bu yüzden işe yaradığını biliyorum!


4

Python - 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`

İlk argüman ile for(ve inve üçüncüsü) bir liste kavramasında, ayrıştırıcı tarafından ayrılabildiği sürece (bir değişken adı kullanmadan), boşluklar isteğe bağlıdır . -2 karakter var.
Nick T

4

Perl, 53 karakter

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

4

89 # 77 karakter

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

Okunabilirlik için biçimlendirilmiş:

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

Bir veya üç ile çarpmıyoruz, sadece her şeyi ekliyoruz, artı tüm yerleştirilmiş karakterleri bir kez daha, iki ile çarpıyoruz.

9992, ASCII karakterlerinin toplamının bundan daha az olması için yeterince büyüktür (böylece, 10'a kadar mod yapabilir ve sonucun pozitif olduğundan, iki kere 10'a mod atmaya gerek kalmayacağından emin olabiliriz) ve sıfır ile bölünemez. tüm bu fazladan 2 * 12 * 48 (1 ve 3 ağırlığında on iki ASCII hanesi) == 1152, bu da bir tane daha fazla karakter kullanmamıza izin veriyor (iki kere 48'i çıkarmak yerine, 0'dan sadece karakterden int'ye çevirmek için, ama 990 yerine 9992 yazmamız gerekiyor.

Ama sonra yine, daha az güzel olsa da ;-), bu eski okul çözümü bizi 80 karaktere çıkardı (ancak bu neredeyse C uyumludur):

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'

Örneğin

f '978030640615'
9780306406157

eski yol:

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

1
(i.12)(".@{)ydeğiştirilebilir"."0 y
J Guy

3

Yakut - 80 karakter

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 karakter

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

Olarak Çağır lIxörn:

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


2

D - 97 karakter

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

Daha okunaklı biçimlendirilmiş:

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'nin oyuncu kadrosunun detayı kesinlikle takıntılı olarak kısa kod yazmayı zorlaştırıyor.


2

Java - 161 Karakterler :(

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

Bir işlev olmadığı için bu cevap ilk gereksinimi karşılamıyor.
han,

1

S (44 karakter)

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

Bu aslında yanlış olduğunu düşünüyorum
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)

Test yapmak:

val isbn="978030640615"
b(isbn)

Sonuç:

"9780306406157"

1

C, 80 79 karakter

İşlev, dizeyi yerinde değiştirir, ancak sorun gereksinimlerini karşılamak için orijinal dize işaretçisini döndürür.

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

Bazı açıklamalar: 0Her bir giriş karakterinden 48'in (hanenin ASCII değeri) çıkarılması yerine , akümülatör s, 48 + 3 * 48 + 48 + 3 * 48 ... + 48 + 3'e eşit modulo 10 olacak şekilde başlatılır. * 48 = 24 * 48 = 1152. Ekleme yerine çıkarma işlemiyle 10-sumbiriktirilerek adımdan kaçınılabilir s. Bununla birlikte, %C'deki modül operatörü , eğer snegatifse kullanılabilir bir sonuç vermez , bu nedenle s-=, 3 ve 1 çarpanlarını kullanmak yerine , sırasıyla -3 = 7 modulo 10 ve -1 = 9 modulo 10 kullanılır.

Test kablo demeti:

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

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

kullanın:

String z = "978030640615"
println i(z)

-> 9780306406157

1

APL (25)

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

Algo 10 ile bitmeli | çünkü 0 yerine 10 yerine geri dönebilirdi
RosLuP

1

Perl 6 , 29 bayt

{$_~-:1[.comb «*»(1,3)]%10}

Çevrimiçi deneyin!


Yani baz 1 toplamın yerine kullanılabilir mi? İlginç!
Jo King,

2
@JoKing Bu aslında APL ve J dünyasında çok eski bir numaradır :)
Bubbler

978186197371 için yanlış sonuç 8 değil 9 gibi görünüyor ...
RosLuP

Pardon, yanlış numarayı yapıştırdığımı düşünüyorum
RosLuP

1

Python 2 , 78 76 bayt

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

Çevrimiçi deneyin!

Argüman olarak dize alır.

Açıklama:

Python dilim gösterimini kullanarak, bir dizgiyi karakter çiftleri listesine dönüştürür. ("978030640615" -> [("9", "7"), ("8", "0"), ("3", "0"), ("6", "4"), ("0 "," 6 "), (" 1 "," 5 ")])

Bu çift listesi için her öğeyi bir tam sayıya dönüştürür ve bir + 3b döndürür.

Tüm sonuçları toplar.

Kalan 0 ise toplam modulo 10, OR 10 alır. (Bu, son hanenin 0 yerine 10 olmasını engeller)

Kontrol hanesini almak için kalanı 10'dan kaldırır.

Hesaplanan kontrol basamağını kullanımdan kaldırılan backtick ifadesiyle bir dizgeye dönüştürür.

Orijinal sayı ile hesaplanan kontrol basamağını döndürür.

Düzenle:

Boşluk kaldırarak 2 byes kurtarıldı (teşekkürler Jo King !).


Önce boşlukları kaldırabilirsiniz forveor
Jo King

Bana göre, 978186197371, 8 rakamının 9 ve 9 rakamının son rakamına ulaştı ... Apl
çözümümde

Pardon, yanlış numarayı yapıştırdığımı düşünüyorum ...
RosLuP

1

APL (Dyalog Unicode) , 18 bayt SBCS

Anonim tacit önek işlevi argüman olarak dize alarak. Bubbler'ın yaklaşımını kullanarak .

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

Çevrimiçi deneyin!

 tartışma uzunluğu (12)

9 7⍴⍨ döngüsel [9,7]olarak bu uzunluğa yeniden şekillendirme

+.× Şununla nokta ürünün çarpımı:

⍎¨ `her karakteri değerlendir

10| bunun mod-10'u

,∘⍕ bunun dizilimini aşağıdakileri hazırlayın:

 değiştirilmemiş tartışma


1

dc , 25 bayt

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

Çevrimiçi deneyin!

Burada zaten bir dc cevabı olduğunu biliyorum, ama 25 <44 sanırım bu konuda 19 bayt hissediyorum. Bu, z'nin çift mi yoksa tek mi olduğuna bağlı olarak 8+9^zya -3da -1mod 10'a eşdeğer olan gerçeği kullanır . Bu yüzden A~sayıyı yığındaki sayılara bölmek için kullanıyorum , ancak yığını oluştururken her basamağı 8+9^zz'nin mevcut yığın büyüklüğü ile çarpıyorum. Sonra hepsini fonksiyon yığını açarken ekledim ve son basamağı yazdırdım.


0

MATLAB - 82 karakter

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

0

R, 147 karakter

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="")}

Kullanımı:

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

0

J, 25

,[:":10|0(-+/)"."0*1 3$~#
   f =:, [: ": 10 | 0 (- + /)". "0 * 1 3 $ ~ #
   f '978030640615'
9780306406157
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.