Konwersja ISBN-13 na ISBN-10

21

Wprowadzenie

W tym wyzwaniu Twoim zadaniem jest wygenerowanie kodu ISBN-10 dla książek, biorąc pod uwagę jego kod ISBN-13, przy założeniu, że taki kod istnieje. Taki kod ISBN-13 składa się z kilku części oddzielonych -:

978-GG-PPPP-TTT-C

Litery G(grupa), P(wydawca), T(tytuł) i C(suma kontrolna) oznaczają jedną cyfrę. Na potrzeby tego wyzwania grupowanie i obliczanie C(patrz to wyzwanie ) nie są interesujące, a my upuszczamy wszystkie łączniki, aby uprościć to zadanie.

Numer ISBN-10 ma bardzo podobny układ:

GG-PPPP-TTT-c

Litery G, Pi Tsą takie same jak dla 13 cyfr ISBN, jednak cróżni się (i jest obliczany przy użyciu innego algorytmu). Cyfra cjest wybierana w taki sposób, aby zachowała się następująca równoważność (cyfry w kolejności):

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

Przykład

Rozważmy numer ISBN 9780345391803: Aby uzyskać odpowiadający mu kod ISBN-10 po prostu upuścić wiodącym 978i suma kontrolna 3plonowanie 034539180.

Następnie musimy obliczyć nową sumę kontrolną:

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

Następną liczbą podzielną przez 11jest 187więc nowa suma kontrolna, 2a tym samym wynikowy kod ISBN-10 0345391802.

Zasady

  • Twój wpis zawsze będzie miał odpowiedni numer ISBN-10 (tzn. Ma dokładnie 13 cyfr i zaczyna się od 978)
  • Dane wejściowe niekoniecznie muszą być poprawne ISBN-13 (np. 9780000000002)
  • Masz gwarancję, że wynikowy numer ISBN się nie skończy X
  • Możesz przyjmować dane wejściowe jako liczbę całkowitą lub ciąg znaków (z łącznikami lub bez), jednak wstępnie obliczona lista cyfr jest niedozwolona
  • Twój wynik musi być poprawnym numerem ISBN-10 (z łącznikami lub bez)
  • Twój wynik może być liczbą całkowitą lub łańcuchem (ponownie bez list cyfr)

Przypadki testowe

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

Uwaga wiodące zera!

ბიმო
źródło
5
W ogóle nie wpływa to na rozwiązania, ale tylko dlatego, że jesteś tym facetem, twój opis tego, jak części ISBN (-10 lub -13) są rozdzielone, jest niepoprawny. Element grupy rejestracyjnej ma zmienną długość, a liczba cyfr dla kolejnych części może się różnić między grupami rejestracyjnymi i wewnątrz nich. Na przykład zarówno w pierwszej , jak 0-684-84328-5i 99921-58-10-7pierwszej części ( 0i 99921odpowiednio) jest grupa rejestracyjna, druga część to wydawca i tak dalej.
Jordan
5
10 przykładowych wyborów ISBN
Jakob

Odpowiedzi:

10

Retina ,  44  39 28 bajtów

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

_

Wypróbuj online!

Wyjaśnienie

Czas pochwalić się nowymi funkcjami Retina. :)

>,L3,-2`.+

Dopasowujemy całe dane wejściowe .+, zwracamy to dopasowanie L, ale wybieramy tylko znaki od 3 (od zera) do -2 (przedostatnie) włącznie. Drukujemy również wynik bez końcowego linefeed ( >).

Odejmowanie rzeczy w Retinie jest trochę denerwujące. Ale na szczęście pracujemy modulo 11, więc możemy po prostu odwrócić współczynniki kombinacji liniowej (mod 11) i zsumować wszystko. Innymi słowy, jeśli ograniczenie jest następujące:

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

wtedy otrzymujemy:

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

To bardzo upraszcza rzeczy tutaj:

.
$.>`**

Zastępujemy każdą postać tą rzeczą na dole. *jest operatorem powtarzania Retiny. Jest asocjacyjnie prawy i ma ukryte operandy $&po lewej i _po prawej stronie, więc podstawienie jest w rzeczywistości krótkie $.>`*$&*_. $&*_tworzy ciąg d podkreślników, gdzie d jest cyfrą, którą obecnie zastępujemy. Następnie $.>`jest długość ciągu do dopasowania włącznie. 1 Stąd całe wyrażenie powoduje jednoznaczne przedstawienie n- tego terminu naszej kombinacji liniowej.

_{11}

Wykonanie rzeczywistego modulo jest jednoznaczne: po prostu upuszczamy wszystkie komplety 11 znaków podkreślenia.

_

Na koniec liczymy, ile jeszcze znaków podkreślenia, i drukujemy wynik, który uzupełnia ISBN-10.


1 W jaki sposób $.>`podaje się długość ciągu aż do dopasowania? Możesz być zaznajomiony z $`podstawieniami wyrażeń regularnych, które dają ci ciąg do (ale z wyłączeniem) dopasowania. Wstawiając >możemy przesunąć kontekście $`do separatora między bieżącym i następnym meczu (który jest pusty ciąg cyfr pomiędzy bieżącym i następnym). Separatory $`będą obejmować bieżące dopasowanie. Więc $>`jest krótsza droga do pisania $`$&. Na koniec, w przypadku $xelementów podstawienia wszystkich typów Retina pozwala wstawić znak .po, $aby uzyskać jego długość.

Martin Ender
źródło
Czym jest magia modulo 11 ?! Zaoszczędzi mi to 4 bajty ... ale nie dostaję tytułu!
streetster
1
@streetster Zasadniczo -2 ≡ 9 (mod 11)(ponieważ dodawanie lub odejmowanie 11 od liczby nie zmienia jej „wartości” w klasie 11 mod zgodności). Dodawanie i mnożenie uwzględnia klasy zgodności, dzięki czemu można zastąpić dowolną wartość w kombinacji liniowej równoważną wartością w ramach bieżącego modułu. Powodem, dla którego mówię o liczbach ujemnych, jest tak naprawdę to, że przestawiłem równanie tak, aby mieć je cz jednej strony, a wszystkie inne terminy (jako negatywy) z drugiej.
Martin Ender
I pomyśleć , że dostać go teraz. Więc przechodzisz cdo stawania się, -c = ...a nie mnożenia przez 10 9 8...odejmowanie 11od każdego z nich, aby uzyskać, -1 -2 -3...a następnie mnożenie wszystkiego przez -1, aby uzyskać c.
streetster
Czy mógłbyś wyjaśnić, dlaczego ostatni etap zastępuje tylko podkreślenia końcowe? Spędziłem trochę czasu próbując dowiedzieć się, co to powoduje, ale nie mogę tego odtworzyć. Nawiasem mówiąc, ta aktualizacja wygląda niesamowicie, niezła robota!
FryAmTheEggman
1
@FryAmTheEggman Dzięki :) W tym momencie ciąg znaków zawiera tylko podkreślenia. Pierwsze dziewięć cyfr wydrukowaliśmy już w pierwszym etapie.
Martin Ender,
6

05AB1E , 17 15 13 12 bajtów

¦¦¦¨DSƶO11%«

Wypróbuj online!

Wyjaśnienie

¦¦¦            # 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
Emigna
źródło
5

PowerShell , 96 84 bajtów

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

Wypróbuj online!

Pobiera dane wejściowe "$args", dokonuje wyrażenia regularnego, -replaceaby uzyskać tylko odpowiednią część, zapisuje je $xjako ciąg. Następnie charrzucamy to jako tablicę i przeglądamy każdą literę. Wewnątrz pętli wstępnie dekrementujemy $a(domyślnie to 0) i mnożymy zgodnie z obliczeniem sumy kontrolnej. Uwaga rzutowania na int, w przeciwnym razie użyłoby to wartości ASCII.

Następnie -joinłączymy te liczby razem +i potokujemy to iex( Invoke-Expressioni podobnie do eval). Bierzemy to %11i przechowujemy tę sumę kontrolną w $y. Na koniec łączymy łańcuch $x + $yi zostawiamy to w przygotowaniu. Wynik jest niejawny.

Zaoszczędź 12 bajtów dzięki Emignie.

AdmBorkBork
źródło
I naprawdę nie wiem PowerShell, ale myślę, że coś w tym może pracować do 84
Emigna
@Emigna Tak, oczywiście. Arytmetyka modułu i mój mózg nie grają ładnie.
AdmBorkBork
5

Oktawa , 46 41 39 37 bajtów

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

Wypróbuj online!

Kod pobiera dane wejściowe jako ciąg znaków i zwraca ciąg znaków.

Kod dzieli się w następujący sposób:

@(a) tworzy anonimową funkcję.

Dzięki [c=a(4:12) ... ]nam wyodrębnić znaki, które stanowią główny kod, oszczędzając jego kopię cdo późniejszego wykorzystania i dodając kolejną kopię do końcowego łańcucha wyjściowego.

W oparciu o sprytny sposób zamiany @ MartinEnter 10:-1:2na 1:10, możemy łatwo wygenerować ten zakres i przetransponować go, aby uzyskać wektor kolumny. c*(1:10)'dokonuje mnożenia tablicowego wektora wiersza ci wektora kolumny zakresu. Jest to równoważne z mnożeniem elementarnym, a następnie sumowaniem.

Suma kontrolna normalnie polegałaby mod(11-sum,11)na obliczeniu liczby wymaganej, aby suma była wielokrotnością 11. Jednak ponieważ cbył to ciąg znaków, suma będzie faktycznie większa niż powinna być o 2592 (48 * 54), ponieważ pomnożymy przez liczby które były o 48 większe niż rzeczywista wartość.

Kiedy wykonamy modulo, automatycznie pozbędzie się on wszystkich oprócz 7 z tego 2592. Jako taki, i uwzględniając negację zakresu, obliczenia stają się rzeczywiste 48+mod(7+sum,11). Dodajemy 48 do wyniku w celu konwersji z powrotem na znak ASCII.

Znak sumy kontrolnej jest dołączany na końcu wyniku i zwracana jest wartość.

Tom Carpenter
źródło
5

Galaretka , 12 bajtów

ṫ4ṖȮV€xJS%11

Jest to pełny program, który używa ciągów dla operacji we / wy.

Wypróbuj online!

Jak to działa

ṫ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.
Dennis
źródło
4

JavaScript (ES6), 59 56 bajtów

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

-3 bajty dzięki sugestii @ Shaggy .

darrylyeo
źródło
57 bajtów ?
Kudłaty
1
A może nawet 56 bajtów .
Kudłaty
Dlaczego więc nie wprowadzić jako tablicy cyfr? 54 bajty
tsh
3

Pyth , 16 bajtów

%s.e*ksbpP>Q3hT

Wypróbuj tutaj!

Pyth , 17 bajtów

%s*VsMKpP>Q3SlK11

Wypróbuj tutaj!

Wyjaśnienie

%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.
Pan Xcoder
źródło
3

Japt , 16 15 bajtów

Przyszedł do tego pubu innej nocy i zupełnie o tym zapomniał.

s3J
U+¬x_*°TÃuB

Spróbuj

Kudłaty
źródło
Myślisz, że możesz uratować bajt za pomocą s3JiU+¬x_*°TÃuB
ETHproductions
Dziwne; mógłbym przysiąc, że tego spróbowałem. Dzięki, @ETHproductions.
Kudłaty
Zaczekaj, nie, zapomniałem U- D'oh!
Kudłaty
3

Sześciokąt , 77 61 bajtów

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

Wypróbuj online!


Kolorowy:


Oto większa wersja. Istnieje kilka skrzyżowań ścieżek, ale ponieważ wszystkie te komórki są .(brak sześciokątów), nie musisz się o nie martwić:

(Próbowałem również zachować stare lustra, ale czasami muszę coś zmienić)

Wykonywane polecenie liniowe to:

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

Objaśnienie: Zamiast utrzymywać licznik i pomnożyć każdą cyfrę, ten program:

  • zachowaj zmienną „suma częściowa” i zmienną „suma całkowita” ( pi t)
  • dla każdej odczytanej cyfry: dodaj ją do sumy częściowej i dodaj sumę częściową do sumy całkowitej.
  • drukuj (-p-t)%11, gdzie %zawsze zwracają pozytywne wyniki.
użytkownik202729
źródło
3

K (oK) , 29 25 24 23 bajtów

Rozwiązanie:

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

Wypróbuj online!

Przykłady:

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"

Wyjaśnienie:

Ocena jest przeprowadzana od prawej do lewej.

Dwie sztuczki zaczerpnięte z innych rozwiązań:

  • pomnóż przez 1 2 3 ... zamiast 10 9 8 ...
  • pomnóż wartości ASCII, a następnie dodaj 7 do sumy, aby zrównoważyć

Awaria:

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

Uwagi:

  • -4 bajty dzięki magii Martina Endersapo prostu odwraca współczynniki ”.
  • -1 bajt dzięki Tomowi Carpenterowi za usunięcie potrzeby konwersji na liczby całkowite (poprzez dodanie 7do sumy)
  • -1 bajt uruchomić akumulator o 7
streetster
źródło
3

C (gcc), 96 95 87 86 85 bajtów

(-1 dzięki 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;}

Wypróbuj online!

Można go nazwać as f(s), gdzie sjest wskaźnikiem do pierwszego elementu modyfikowalnej tablicy znaków. Modyfikuje tablicę wejściową, zwraca wskaźnik do tablicy wejściowej.

hvd
źródło
2

Python 2 , 62 bajty

lambda n:n[3:12]+`-sum(i*int(n[13-i])for i in range(2,11))%11`

Wypróbuj online!

Pobiera ciąg jako dane wejściowe; i wyprowadza ciąg.

Chas Brown
źródło
2

ECMAScript 6 , 86 67 bajtów

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

Wypróbuj online!


Dzięki za komentarz Arnaulda , zmieniono z reducena mapi pozbyłem się returnsłowa kluczowego.

Kos
źródło
3
Witamy w PPCG! Odpowiedzi muszą być pełnymi programami lub funkcjami wywoływalnymi (chociaż mogą to być funkcje bez nazwy), a nie tylko fragmentami. Uważam, że najkrótszą opcją w JavaScript jest zwykle nienazwana lambda.
Martin Ender
@MartinEnder dzięki, zredagowałem swoją odpowiedź
Kos
3
Witaj na pokładzie! Niektóre wskazówki: Zmienna inicjalizacji zazwyczaj można umieścić jako dodatkowych parametrów map(), reduce()itp z dodatkowymi przepisywanie, to często możliwe, aby pozbyć {}i return. Również w tym konkretnym przypadku map()jest prawdopodobnie krótszy niż reduce(). ( Oto wersja 65-bajtowa.)
Arnauld
Jestem pewien, że f=nie jest to konieczne. Możesz także zainicjować cna rozkładówce coś takiego:a=>{i=10;s=[...c=a.substr(3,9)].reduce((g,v)=>+g+(i--)*v,0)%11;return c+=s?11-s:0} (-4 bajty)
Asone Tuhid
2

Retina 0.8.2 , 72 51 bajtów

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

¶(1*)
$.1

Wypróbuj online! Ponieważ jeszcze nie nauczyłem się Retina 1.0. Wyjaśnienie:

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

Usuń niepotrzebne znaki i zrób drugą kopię odpowiednich cyfr.

r`.\G
$&$'

Dodawaj każdą cyfrę w drugiej kopii sufiksem. To skutecznie powtarza każdą cyfrę w sufiksie według pozycji.

r`.\G
$*

Konwertuj cyfry w drugiej kopii na jednoargumentowe, dodając je razem.

1{11}

Zmniejsz moduł 11. (W pierwszym egzemplarzu jest tylko 9 cyfr, więc to nigdy nie ma na to wpływu).

¶(1*)
$.1

Przekształć wynik z powrotem na dziesiętny i ponownie usuń znak nowej linii.

Neil
źródło
2

APL (Dyalog Unicode) , 26 24 bajtów

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

Wypróbuj online!

Funkcja ukrytego przedrostka. Pobiera dane wejściowe jako ciąg.

2 bajty zapisane dzięki @ngn.

W jaki sposób?

∊⍕¨(⊢,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.
J. Sallé
źródło
1

Czysty , 104 102 98 bajtów

import StdEnv
$s#s=s%(3,11)
#i=sum[digitToInt d*p\\d<-s&p<-[10,9..]]+10
=s++[toChar(i/11*11-i+58)]

Wypróbuj online!

Obrzydliwe
źródło
1

Kotlin , 83 bajty

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

Upiększony

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

Test

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

jrtapsell
źródło
1

Rubin , 69 68 64 bajtów

->n{v=n[3,9];c=11;v+"#{(c-v.chars.map{|i|i.to_i*c-=1}.sum)%11}"}

Wypróbuj online!

Asone Tuhid
źródło
1

PHP, 64 bajty

Niestety w PHP (-$c)%11jest taki sam jak -($c%11); więc muszę uzyskać różnicę do co najmniej największej możliwej kwoty (55 * 9 = 495 = 45 * 11) zamiast po prostu użyć -$c%11.

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

lub

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

Uruchom jako potok z -nRlub wypróbuj je online .

Tytus
źródło
0

Java 10, 110 bajtów

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

Pobiera dane wejściowe i wyjściowe jako longliczbę całkowitą. Wypróbuj online tutaj .

Wersja bez golfa:

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
}
OOBalance
źródło