Przetwarzaj kwaternion

27

Jeśli jeszcze nie wiesz, czwartorzęd jest w zasadzie liczbą 4-częściową. Na potrzeby tego wyzwania ma prawdziwy komponent i trzy fikcyjne komponenty. Wyimaginowanych części są reprezentowane przez sufiks i, j, k. Na przykład, 1-2i+3j-4kjest kwaternion z 1czym składowa rzeczywista i -2, 3i -4jest z urojonych.

W tym wyzwaniu musisz przeanalizować ciąg znaków czwartorzędu (np. "1+2i-3j-4k") Na listę / tablicę współczynników (np. [1 2 -3 -4]). Ciąg czwartorzędu można jednak sformatować na wiele różnych sposobów ...

  • To może być normalne: 1+2i-3j-4k
  • To może mieć brakujące warunki: 1-3k, 2i-4k(Jeśli masz brakujące warunki, wyjście 0dla tych kategoriach)
  • Może to być brak współczynników: i+j-k(W tym przypadku, jest to równoznaczne z 1i+1j-1kInnymi słowy,. i, jLub kbez numeru przed zakłada się mieć 1przed domyślnie)
  • Może nie być w odpowiedniej kolejności: 2i-1+3k-4j
  • Współczynniki mogą być po prostu liczbami całkowitymi lub dziesiętnymi: 7-2.4i+3.75j-4.0k

Podczas analizowania należy zwrócić uwagę na kilka rzeczy:

  • Zawsze będą warunki +lub -pomiędzy warunkami
  • Zawsze otrzymasz prawidłowe dane wejściowe z co najmniej 1 terminem i bez powtarzających się liter (bez liter j-j)
  • Wszystkie liczby można przyjąć za prawidłowe
  • Można zmienić numery w inną formę po parsowania jeśli chcesz (np. 3.0 => 3, 0.4 => .4, 7 => 7.0)

Wbudowane parsowanie / quaternion i standardowe luki są niedozwolone. Dotyczy to evalsłów kluczowych i funkcji. Dane wejściowe będą stanowić pojedynczy ciąg, a dane wyjściowe będą listą, tablicą, wartościami oddzielonymi spacjami itp.

Ponieważ jest to kod, wygrywa najkrótszy kod w bajtach.

Mnóstwo przypadków testowych

1+2i+3j+4k             => [1 2 3 4]
-1+3i-3j+7k            => [-1 3 -3 7]
-1-4i-9j-2k            => [-1 -4 -9 -2]
17-16i-15j-14k         => [17 -16 -15 -14]

7+2i                   => [7 2 0 0]
2i-6k                  => [0 2 0 -6]
1-5j+2k                => [1 0 -5 2]
3+4i-9k                => [3 4 0 -9]

42i+j-k                => [0 42 1 -1]
6-2i+j-3k              => [6 -2 1 -3]
1+i+j+k                => [1 1 1 1]
-1-i-j-k               => [-1 -1 -1 -1]

16k-20j+2i-7           => [-7 2 -20 16]
i+4k-3j+2              => [2 1 -3 4]
5k-2i+9+3j             => [9 -2 3 5]
5k-2j+3                => [3 0 -2 5]

1.75-1.75i-1.75j-1.75k => [1.75 -1.75 -1.75 -1.75]
2.0j-3k+0.47i-13       => [-13 0.47 2.0 -3] or [-13 .47 2 -3]
5.6-3i                 => [5.6 -3 0 0]
k-7.6i                 => [0 -7.6 0 1]

0                      => [0 0 0 0]
0j+0k                  => [0 0 0 0]
-0j                    => [0 0 0 0] or [0 0 -0 0]
1-0k                   => [1 0 0 0] or [1 0 0 -0]
GamrCorps
źródło
Czy +na wejściu będą kiedyś niepotrzebne znaki? Jak: +1k?
FryAmTheEggman
@FryAmTheEggman No. dane wejściowe nigdy nie zaczną się od +.
GamrCorps
1
Czy -0część legalnych wyników dla dwóch ostatnich przykładów?
isaacg
1
@isaacg tak, w porządku
GamrCorps
1
@LLlAMnYP Podnosisz dobry punkt. Pozwala zdefiniować evalograniczenie, które ma być ciągiem, interpretowane jako kod i / lub dane wejściowe. Wszelkie konwersje nie liczą się do tego, ponieważ nie można przekazać, na przykład, ciągu "test"do funkcji konwersji na liczbę całkowitą, aby otrzymać liczbę całkowitą, ale testbyłby interpretowany jako kod w normalnej evalfunkcji. TLDR: eval: nie, konwersje typu: tak.
GamrCorps

Odpowiedzi:

5

Pyth, 48 bajtów

jm+Wg\-K--e|d0G\+K1+]-I#GJczfT.e*k<b\.zm/#dJ"ijk

Pakiet testowy demonstracji

Format wyjściowy jest oddzielony znakiem nowej linii. Kod zestawu testów używa separacji spacji dla ułatwienia odczytu, ale poza tym jest taki sam.

Wyprowadza a -0w ostatnich 2 przypadkach, które, mam nadzieję, są w porządku.

Wyjaśnienie do naśladowania.

isaacg
źródło
9

Retina, 115

\b[ijk]
1$&
^(?!.*\d([+-]|$))
0+
^(?!.*i)
+0i+
^(?!.*j)
0j+
^(?!.*k)
0k+
O$`[+-]*[\d.]*(\w?)
$1
-
+-
^\+

S`[ijk+]+

Wypróbuj online!

1 bajt zapisany dzięki @Chris Jester-Young .

Naprawiono błąd i zapisano 6 bajtów dzięki @Martin Büttner

Znaleziono kilka błędów związanych z niektórymi przypadkami na krawędziach, dość mocno zwiększona liczba bajtów.

Zwraca liczby oddzielone nową linią. Tak czy inaczej, to ma w większości eleganckie rozwiązanie, które w pewnym sensie jest niszczone przez skrzynki, ale hej, muszę użyć trybu sortowania, co oznacza, że ​​użyłem odpowiedniego narzędzia do pracy, prawda?

Wyjaśnienie:

Krok po kroku, jak zwykle.

\b[ijk]
1$&

Jedynymi znakami na wejściu, które mogą tworzyć granice słów, są -+.. Oznacza to, że jeśli znajdziemy granicę, po której następuje litera, mamy domniemanie, 1które dodajemy wraz z zamiennikiem. $&jest synonimem $0.

^(?!.*\d([+-]|$))
0+

Ogromne podziękowania dla Martina za ten, ten dodaje domyślną 0prawdziwą część, jeśli jej brakowało w danych wejściowych. Upewniamy się, że nie możemy znaleźć liczby, po której następuje znak plus lub minus lub koniec łańcucha. Wszystkie liczby zespolone będą miały literę po nich.

^(?!.*i)
+0i+

Kolejne 3 etapy są prawie takie same, z wyjątkiem tego, na którą literę wpływają. Wszyscy sprawdzają, czy nie możemy dopasować litery, a jeśli nie, możemy dodać do niej 0termin. Jedynym powodem ijest to, +że nie można odczytać rzeczywistej wartości ze iwspółczynnikiem s, pozostałe liczby są oddzielone ich zmienną zespoloną.

O$`[+-]*[\d.]*(\w?)
$1

Ach, zabawna część. Wykorzystuje to nowy etap sortowania, oznaczony przez backstick Oprzed separatorem opcji. Sztuką jest złapanie całej liczby, po której opcjonalnie występuje znak słowny, który w tym przypadku będzie pasował tylko do jednego ijk. Inną zastosowaną opcją jest $zamiana wartości użytej do sortowania tych dopasowań. W tym przypadku używamy opcjonalnej litery, która pozostała jako nasza wartość sortowania. Ponieważ Retina domyślnie sortuje leksykograficznie, wartości są sortowane tak, jakby były w słowniku, co oznacza, że ​​dopasowujemy "", "i", "j", "k"kolejność.

-
+-

Ten etap umieszcza +znak przed wszystkimi znakami minusowymi, jest to potrzebne, jeśli ipóźniej będziemy mieli wartość ujemną dla etapu podziału.

^ \ +

Usuwamy wiodące, +aby upewnić się, że nie mamy dodatkowych wiodących nowych linii.

S`[ijk+]+

Podziel pozostałe linie na przebiegach zmiennych zespolonych lub znaku plus. To ładnie daje nam jedną wartość na linię.

FryAmTheEggman
źródło
3

Perl 5, 125 bajtów

#!perl -p
%n=(h,0,i,0,j,0,k,0);$n{$4//h}=0+"$1@{[$3//$5//1]}"while/([+-]?)(([\d.]+)?([ijk])|([\d.]+))/g;s/.*/@n{qw(h i j k)}/
Chris Jester-Young
źródło
1
@KennyLau Niestety, proponowana zmiana nie spełnia oczekiwań. Próbowałem tego, zanim opublikowałem swoją odpowiedź. ;-)
Chris Jester-Young
@KennyLau Jeśli chodzi o proponowaną zmianę , Perl \adopasowuje „alarm”, a nie alfabetycznie. Dostępne są \wznaki słowne (alfanumeryczne i podkreślniki), ale to tutaj nie zadziała; potrzebujemy, aby nie pasowała do numeru.
Chris Jester-Young
3
@KennyLau BTW, masz wystarczającą liczbę przedstawicieli, aby rozmawiać na czacie . Możesz omawiać tam pomysły, a nie odrzucać sugestii dotyczących edycji. ;-)
Chris Jester-Young
Mam też wystarczającą liczbę przedstawicieli, aby skomentować. Czy Perl nie ma wzorca dla [az]?
Leaky Nun
1
@KennyLau Nie według mojej wiedzy.
Chris Jester-Young
3

Lua , 185 187 195 183 166 bajtów ( wypróbuj online ) [używane wyrażenie regularne]

Dzięki @Chris Jester-Young za ulepszony regex.

Dzięki @Katenkyo za sprowadzenie go do 166 bajtów.

Gra w golfa:

r={0,0,0,0}for u in(...):gsub("([+-])(%a)","%11%2"):gmatch("-?[%d.]+%a?")do n,i=u:match("(.+)(%a)")r[i and(" ijk"):find(i)or 1]=(n or u)end print(table.concat(r," "))

Nie golfowany:

n = "42i+j-k+0.7"

result = {0,0,0,0}

for unit in n:gsub("([+-])(%a)","%11%2"):gmatch("-?[%d.]+%a?") do
  num, index = unit:match("(.+)(%a)")
  if index == "i" then
    result[2] = num
  elseif index == "j" then
    result[3] = num
  elseif index == "k" then
    result[4] = num
  else
    result[1] = unit
  end
end

print(table.concat(result," "))
Leaky Nun
źródło
2
Cześć Kenny, dzięki za rozwiązanie. Zwykle nie zezwalamy na dane wejściowe rozpoczynające się od zmiennej (jak nw tym przypadku), dlatego należy dodać kod, aby odczytać dane wejściowe.
isaacg
Powinieneś być w stanie zaoszczędzić trochę bajtu, zmieniając dane wejściowe z STDIN na argument, zamiast io.read()użycia (...). Będzie wskazywał na pierwszy argument wiersza poleceń i pozwoli ci zaoszczędzić 4 kolejne bajty :)
Katenkyo
1
Zapytany wynik może być dowolny, o ile może być interpretowany przez ludzi jako lista, dzięki czemu można usunąć dodatkowe formatowanie. Łącznie z kilkoma białymi spacjami, które możesz zgolić, twój kod może spaść do 166 bajtów ->r={0,0,0,0}for u in(...):gsub("([+-])(%a)","%11%2"):gmatch("-?[%d.]+%a?")do n,i=u:match("(.+)(%a)")r[i and(" ijk"):find(i)or 1]=(n or u)end print(table.concat(r," "))
Katenkyo
3

C, 236 bajtów

char j,n[9][9],s[9],y[9],i=8,k,*p=n[8];main(c){for(**n=48;c=getchar(),c+1;)c-32&&(c<46&&(k&&(y[1]=i),k=0,s[--i]=c-43,p=n[i])||c>57&&(k||(*p=49),k=0,y[c-103]=i)||(*p++=c,k=1));for(k&&(y[1]=i);++j<5;)printf("%c%s ",s[y[j]]?45:0,n[y[j]]);}

(W przypadku wartości takich jak -0 lub -0,0 znak wyjściowy jest również drukowany na wyjściu, ale ponieważ wyzwanie mówi, że „możesz zmienić liczby na inną formę po parsowaniu, jeśli chcesz”, a jeśli na wejściu pojawi się -0, wynika z tego, że jest to również dopuszczalne w danych wyjściowych. @GamrCorps wyjaśnił teraz, że jest to w porządku.)

Mllllbyte
źródło
3

JavaScript (ES6), 103 100 bajtów

f=s=>s.replace(/(?=.)(\+|-|)([\d.]*)(\w?)/g,(_,s,x,c)=>a[c.charCodeAt()&3]=+(s+(x||1)),a=[0,0,0,0])&&a

Edycja: Zapisałem 3 bajty, przełączając się z parseIntna charCodeAt, który wygodnie wystarczy, &3aby uzyskać poprawny indeks tablicy.

Neil
źródło
Fajny pomysł parseInt + mod. Myślenie o bazie i prefiksie
edc65
1

JavaScript (ES6) 106

s=>(s.replace(/([+-]?)([\d.]*)(\w?)/g,(a,b,c,d)=>a&&(s[d||9]=b+(c||1)),s={}),[...'9ijk'].map(i=>+s[i]||0))

Test

f=s=>(s.replace(/([+-]?)([\d.]*)(\w?)/g,(a,b,c,d)=>a&&(s[d||9]=b+(c||1)),s={}),[...'9ijk'].map(i=>+s[i]||0))

function Test()
{
  var t,k,r,ts=TS.value.split('\n')
  
  O.textContent=ts.map(x=>x.trim()&&(
    [t,k]=x.split('=>').map(x=>x.trim()),
    console.log(t,'*',k),
    k=k.match(/[\d+-.]+/g).map(x=>+x),
    r=f(t),
    t+' => '+r+(r+''==k+''?' OK':' KO (check: '+k+')')
  )).join('\n')
}    

Test()
#TS { width:90%; height:10em}
<pre id=O></pre>

Test data (modify if you like)<button onclick='Test()'>repeat test</button>
<textarea id=TS>
1+2i+3j+4k             => [1 2 3 4]
-1+3i-3j+7k            => [-1 3 -3 7]
-1-4i-9j-2k            => [-1 -4 -9 -2]
17-16i-15j-14k         => [17 -16 -15 -14]
  
7+2i                   => [7 2 0 0]
2i-6k                  => [0 2 0 -6]
1-5j+2k                => [1 0 -5 2]
3+4i-9k                => [3 4 0 -9]
  
42i+j-k                => [0 42 1 -1]
6-2i+j-3k              => [6 -2 1 -3]
1+i+j+k                => [1 1 1 1]
-1-i-j-k               => [-1 -1 -1 -1]
  
16k-20j+2i-7           => [-7 2 -20 16]
i+4k-3j+2              => [2 1 -3 4]
5k-2i+9+3j             => [9 -2 3 5]
5k-2j+3                => [3 0 -2 5]
  
1.75-1.75i-1.75j-1.75k => [1.75 -1.75 -1.75 -1.75]
2.0j-3k+0.47i-13       => [-13 0.47 2.0 -3]
5.6-3i                 => [5.6 -3 0 0]
k-7.6i                 => [0 -7.6 0 1]
  
0                      => [0 0 0 0]
0j+0k                  => [0 0 0 0]
-0j                    => [0 0 0 0]
1-0k                   => [1 0 0 0]
</textarea>

edc65
źródło
0

PowerShell, 178 bajtów

param($a);$p="(-?)([\d.]+)?";$g={param($s)if($a-match"$p$s"){if(($r=$matches)[2]){$r[1]+$r[2]}else{$r[1]+1}}else{0}};$a-match"$p(\+|-|$)">$null;+$matches[2];"i","j","k"|%{&$g $_}

Niegolfowany z wyjaśnieniem

# Get the whole string into a variable
param($a)
# Pattern shared getting both imaginary and real numbers. 
$p="(-?)([\d.]+)?"
# Anonymous function that will locate a imaginary number using a letter sent as a parameter. 
# If no value is assigned a signed 1 is returned. If no value is matched 0 is returned
$g={param($s)if($a-match"$p$s"){if(($r=$matches)[2]){$r[1]+$r[2]}else{$r[1]+1}}else{0}}
# Locate the real component if any. Null is converted to 0
$a-match"$p(\+|-|$)">$null;+$matches[2]
# Call the anonymous function using each of the imaginary suffixes.                                               
"i","j","k"|%{&$g $_}

Nie jestem pod wrażeniem, ale mimo wszystko jest to wynik.

Matt
źródło
0

PHP, 179 bajtów

$a=[''=>0,'i'=> 0,'j'=>0,'k'=>0];preg_match_all("/([-+]?)(\d*(\.\d+)?)([ijk]?)/",$argv[1],$m,2);foreach($m as$n)if($n[0])$a[$n[4]]=$n[1].($n[2]===''?1:$n[2]);echo implode(',',$a);

Wypróbuj zestaw testowy .

nickb
źródło
0

Python 3.5 - 496 bajtów [przy użyciu wyrażeń regularnych]:

from re import*
def wq(r):
 a=sub('[+](?![0-9])','+1',sub('[-](?![0-9])','-1',r));q=lambda x:(not x.isdigit(),''.join(filter(str.isalpha,x)))
 for z in findall('(?<![0-9])[a-z]',a):a=a.replace(z,('+1{}'.format(z)))
 if not str(sorted(((sub('[.]','',sub('[+-]',' ',a))).split(' ')),key=q)[0]).isdigit():a+='+0, '
 for i in list(set(findall('[a-z]',a))^{'i','j','k'}):a+='+0{}, '.format(i)
 print(findall('[-]?\d+(?:\.\d+)?',''.join(sorted(sub('(?<=[A-Za-z0-9])(?=[+-])',', ',a).split(' '),key=q))))

To może być długie, ale w mojej obronie działa idealnie, robiąc to, czego chce OP, ponieważ wszystkie podane przypadki testowe zakończyły się powodzeniem przy użyciu mojego kodu.

Wersja bez golfa z wyjaśnieniem zawiera:

from re import*
def w(r):
    # Substitute all minus (-) and plus (+) signs NOT followed by a number  (if there are any) with a "-1"/"+1", respectively.
    a=sub('[+](?![0-9])','+1',sub('[-](?![0-9])','-1',r))
    # Lambda function created for later use to sort the Quaternion. This function, when given as a key to the "sorted" function, arranges the input Quaternion in the order where the whole number comes first, and then the rest are placed in order of increasing letter value (i,j,k in this case) 
    q=lambda x:(not x.isdigit(),''.join(filter(str.isalpha,x)))
    # The following "for" loop replaces the letters NOT preceded by a number with a one followed by that letter
    for z in findall('(?<![0-9])[a-z]',a):
        a=a.replace(z,('+1{}'.format(z)))
    # The following first substitutes all pluses and minuses (+ and -) with a space, and then that new string is split at those spaces, and returned as a list. After that, the list is sorted according the the "lambda" function shown above. Then, the first item in that list, which is supposed to be a lone number, is checked to make sure that it indeed is a lone number. If it isn't, then "+0, " is appended to the Quaternion. 
    if not str(sorted(((sub('[.]','',sub('[+-]',' ',a))).split(' ')),key=q)[0]).isdigit():
        a+='+0, '
    # The following "for" loop finds ALL the letters NOT in the list, by finding the symmetric difference between a set of all the letters found, and a set containing all the letters needed. For the letters not in the list, a '+0' is added the quaternion, followed by that letter, and then a comma and a space.
    for i in list(set(findall('[a-z]',a))^{'i','j','k'}):
        a+='+0{}, '.format(i)
    # Finally, in this last step, a ", " is added IN BETWEEN unicode characters and pluses/minuses (+/-). Then, it splits at those spaces, and the commas separate different parts of the Quaternion from each other (otherwise, you would get something like `12i+3j+4k` from `2i+3j+4k+1`) in a returned list. Then, that list is sorted according to the lambda expression "q" (above), and then, finally, the NUMBERS (of any type, courtesy to Regex) are extracted from that joined list, and printed out in the correct order.
    print(findall('[-]?\d+(?:\.\d+)?',''.join(sorted(sub('(?<=[A-Za-z0-9])(?=[+-])',', ',a).split(' '),key=q))))

Jeśli powyższe jest trochę zbyt trudne do odczytania, w zasadzie dzieje się tak:

  1. Jeśli występują, wszystkie znaki + lub - NIE, po których następuje liczba, są zastępowane odpowiednio przez „+1” / „- 1”.

  2. lambdaFunkcja jest zdefiniowana, który, gdy jest stosowany w sortedfunkcji jako klucza, sortuje listę według oddanie cały numer, a potem zamawianie resztę w zwiększaniu wartości się ( „I”, a następnie „j”, a następnie „k” W tym przypadku).

  3. Czwórnik, w razie potrzeby zastępując teraz wszystkie znaki +/- 1, przeszukuje się za pomocą wyrażeń regularnych WSZYSTKIE litery NIE poprzedzone co najmniej jedną liczbą, a pasujące litery zastępuje się „+1”, po którym następuje ten list.

  4. Instrukcja „if” następnie zastępuje WSZYSTKIE znaki +/- spacją, a następnie zmodyfikowany Quaternion jest teraz „dzielony” w tych spacjach i zwracany na liście. Następnie lista jest sortowana zgodnie z wyjaśnioną wcześniej funkcją lambda. Na koniec sprawdzany jest pierwszy element na tej liście, aby upewnić się, że jest liczbą, ponieważ powinien to być, a jeśli nie, to do czwartorzędu dodaje się „+0”.

  5. Druga pętla „for” znajduje WSZYSTKIE litery NIE w ćwiartce, znajdując symetryczną różnicę między zbiorem liter znajdujących się w wyrażeniu, a następnie zestaw zawierający wszystkie wymagane litery. Jeśli jakieś zostaną znalezione, wówczas „+0”, a następnie brakująca litera i spacja są dodawane do czwartorzędu.

  6. Na koniec, w ostatnim kroku, pomiędzy każdym znakiem dodaje się znak „,”, po którym następuje symbol +/-, a następnie kwatermistrz jest dzielony na te spacje, a następnie zwracana lista jest sortowana, po raz ostatni, zgodnie z funkcja lambda zdefiniowana wcześniej jako „q”. Przecinki w wypowiedzi oddzielić każda część kwaterniony (w przeciwnym razie można byłoby się coś podobnego 14i+5j+6kz 4i+5j+6k+1). Na koniec ta posortowana lista jest następnie łączona w ciąg, a tylko liczby dowolnego typu (dzięki wyrażeniom regularnym) są wyodrębniane i ostatecznie zwracane w postaci listy we właściwej kolejności za każdym razem.

R. Kap
źródło