Розбір кватерніона


27

Якщо ви ще не знаєте, кватерніон - це в основному 4-частинне число. Для цілей цього виклику він має реальний компонент і три уявні компоненти. Уявні компоненти представлені суфіксом i, j, k. Наприклад, 1-2i+3j-4kце кватерніон з 1бути реальним компонентом і -2, 3і -4будучи уявні компоненти.

У цьому виклику ви повинні розібрати струнну форму кватерніона (наприклад "1+2i-3j-4k") у список / масив коефіцієнтів (наприклад [1 2 -3 -4]). Однак рядок кватерніона можна відформатувати різними способами ...

  • Це може бути нормально: 1+2i-3j-4k
  • Він може мати відсутні умови: 1-3k, 2i-4k(якщо у вас є відсутні умови, вихід 0для цих термінів)
  • Це , можливо, відсутні коефіцієнти: i+j-k(В даному випадку, це еквівалентно 1i+1j-1kІншими словами ,. i, jАбо kбез номера перед передбачається мати 1перед за замовчуванням)
  • Це може бути не в правильному порядку: 2i-1+3k-4j
  • Коефіцієнти можуть бути просто цілими чи десятковими числами: 7-2.4i+3.75j-4.0k

Деякі речі слід зазначити під час розбору:

  • Завжди буде термін +або -між ними
  • Ви завжди отримаєте дійсне введення принаймні 1 термін і без повторних літер (без j-js)
  • Усі числа можна вважати дійсними
  • Ви можете змінити номери в іншу форму після розбору , якщо ви хочете (напр. 3.0 => 3, 0.4 => .4, 7 => 7.0)

Вбудовані парсинг / кватерніон та стандартні лазівки заборонені. Сюди входять evalключові слова та функції. Вхід буде єдиним рядком, а вихід буде списком, масивом, значеннями, розділеними пробілом тощо.

Оскільки це , виграє найкоротший код у байтах.

Тести про тести

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]

Чи будуть коли-небудь зайві +знаки у введенні? Як: +1k?
FryAmTheEggman

@FryAmTheEggman Ні. Входи ніколи не почнуться з +.
GamrCorps

1
Чи -0є частиною законних результатів для останніх двох прикладів?
isaacg

1
@isaacg так, це добре
GamrCorps

1
@LLlAMnYP Ви пропонуєте хороший момент. Дозволяє визначити evalобмеження, яке слід приймати в рядку, інтерпретувати як код та / або вхід. Будь-які перетворення не враховуються під цим, оскільки ви не можете передати, наприклад, рядок "test"до цілочисельної функції перетворення для отримання цілого числа, але testбуде інтерпретуватися як код у звичайній evalфункції. TLDR: eval: ні, введіть перетворення: так.
GamrCorps

Відповіді:


5

Pyth, 48 байт

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

Демонстраційний набір тестів

Формат виводу розділений новим рядком. Код тестового набору використовує поділ простору для зручності читання, але інакше той самий.

Виводить a -0в останніх 2 випадках, що, я сподіваюся, що це нормально.

Пояснення слід.


9

Сітківка, 115

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

S`[ijk+]+

Спробуйте в Інтернеті!

1 байт збережено завдяки @Chris Jester-Young .

Виправлено помилку та збережено 6 байт завдяки @Martin Büttner

Знайшли пару помилок, пов’язаних із деякими крайовими справами, досить багато натрапили на кількість байтів.

Повертає номери, розділені рядком. У будь-якому випадку це, в основному, елегантне рішення, яке стає зруйнованим крайовими корпусами, але так, я маю використовувати режим сортування, це означає, що я використовував правильний інструмент для роботи, правда?

Пояснення:

Поетапно, як завжди.

\b[ijk]
1$&

Єдині символи у вводі, які можуть створювати межі слів, - це -+.. Це означає, що якщо ми знайдемо межу, за якою йде буква, у нас є неявна, 1яку ми додаємо із заміною.$&є синонімом для $0.

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

Велика подяка Мартіну за це, це додає неявно 0 за реальну частину, якщо вона відсутня у введенні. Ми переконуємося, що не можемо знайти число, за яким слідує знак плюс або мінус, або кінець рядка. Усі складні цифри будуть мати літеру після них.

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

Наступні 3 етапи майже однакові, забороняючи, яку букву вони впливають. Усі вони дивляться, чи не можемо ми відповідати букві, а чи не можемо ми додати 0термін для цього. Єдина причина i- додаткова+ перед якою є це запобігання нечитабельності реального значення з iкоефіцієнтом s, інші числа розділені їх складною змінною.

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

Аха, весела частина. Для цього використовується нова ступінь сортування, позначена Oпопередньою опцією сепаратора опцій. Хитрість тут полягає в тому, щоб схопити ціле число, за яким необов'язково слідувати символом слова, який у даному випадку завжди буде відповідати лише одному з ijk. Інший варіант, який використовується, полягає в тому, $що значення, яке використовується для сортування цих збігів, є заміною. Тут ми просто використовуємо необов'язковий лист, який залишився як значення сортування. Оскільки Retina сортує лексикографічно за замовчуванням, значення сортуються так, як вони були б у словнику, тобто ми отримуємо збіги у "", "i", "j", "k"порядку.

-
+-

Цей етап ставить +знак перед усіма знаками мінус, це потрібно, якщо iпізніше ми матимемо від’ємне значення на етапі розділення.

^ \ +

Ми видаляємо провідне, +щоб переконатися, що у нас немає зайвого нового рядка.

S`[ijk+]+

Розділіть решта рядків на прогони складних змінних або знак плюс. Це чудово дає нам одне значення на рядок.


3

Perl 5, 125 байт

#!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)}/

1
@KennyLau На жаль, запропонована вами зміна не відповідає тому, що ви очікуєте. Я спробував це, перш ніж розмістити свою відповідь. ;-)
Кріс Єстер-Янг

@KennyLau Щодо цієї запропонованої зміни , Perl \aвідповідає "тривожному", а не за алфавітом. Там є \wслово-символ (буквено-цифровий та підкреслити), але це не працює; нам це потрібно, щоб не збігатися з числом.
Кріс Єстер-Янг

3
@KennyLau BTW, у вас є достатня кількість представників для розмови в чаті . Не соромтеся обговорювати ідеї там, а не постійно відхиляти ваші пропозиції щодо редагування. ;-)
Кріс Єстер-Янг

У мене також є достатня кількість представників для коментарів. Чи Perl не має шаблону для [az]?
Лина монашка

1
@KennyLau Не наскільки мені відомо.
Кріс Єстер-Янг

3

Луа , 185 187 195 183 166 байт ( спробуйте в Інтернеті ) [б / в регекс]

Завдяки @Chris Jester-Young за вдосконалений вираз.

Дякуємо @Katenkyo за те, що він знизив його до 166 байт.

Гольф:

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," "))

Безголівки:

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," "))

2
Привіт Кенні, дякую за рішення. Зазвичай ми не дозволяємо введення починати з змінної (як nу цьому випадку), тому вам слід додати код для читання введення.
isaacg

Ви повинні мати можливість зберегти деякий байт, замість цього io.read()використати свій вхід зі STDIN на аргумент (...). Він вкаже на перший аргумент командного рядка і дозволить вам зберегти ще 4 байти :)
Katenkyo

1
Крім того, запитуваний вихід може бути будь-яким, доки він може бути інтерпретований людьми як список, так що ви можете видалити додаткове форматування. З урахуванням ще кількох пробілів, які ви можете голити, ваш код може знизитися до 166 байт ->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 байт

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

(Для значень, таких як -0 або -0.0, знак мінус також друкується у висновку, але оскільки виклик зазначає, що "ви можете змінити числа в іншу форму після розбору, якщо хочете", і якщо -0 відображається на вході, випливає, що це також прийнятно у висновку. @GamrCorps тепер уточнив, що це нормально.)


3

JavaScript (ES6), 103 100 байт

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

Редагувати. Збережено 3 байти шляхом переходу parseIntв режим charCodeAt, який зручно просто &3для отримання мені правильного індексу масиву.


Приємний аналіз ідеї + мод. Думаючи про базу та префікс
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))

Тест

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>


0

PowerShell, 178 байт

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 $_}

Непорочний з поясненням

# 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 $_}

Не супер вражений, але все-таки результат.


0

PHP, 179 байт

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

Спробуйте набір тестів .


0

Python 3,5 - 496 байт [використовуючи регулярні вирази]:

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

Це може бути довгим, але на мій захист він прекрасно справляється з тим, що хоче ОП, оскільки всі наведені тестові справи були успішними з використанням мого коду.

Версія без вогків із поясненням:

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

Якщо вищезазначене трохи важко читати, то в основному все відбувається так:

  1. Якщо такі є, всі знаки + або - НЕ, за якими слід число, замінюються відповідно "+1" / "- 1".

  2. lambdaВизначаються функція, яка при використанні в sortedфункції в якості ключа, сортує список згідно покласти весь номер перший, а потім наказувати інше в збільшенні листи значення ( «я», а потім «J», то «до» у цьому випадку).

  3. Кватерніон, у якого зараз усі знаки +/- замінені значком 1, шукається, використовуючи регулярні вирази, для ВСІХ букв, які не передують принаймні одним номером, і ті літери, які відповідають, замінюються на "+1", а потім той лист.

  4. Потім оператор "якщо" замінює ВСІ +/- знаками пробілом, а потім модифікований Кватерніон тепер "розбивається" на ці пробіли та повертається у список. Потім список сортується відповідно до функції лямбда, поясненої раніше. Нарешті, перший пункт у цьому списку перевіряється, щоб переконатися, що це число, оскільки воно повинно бути, а якщо його немає, то в Кватерніон додається "+0".

  5. Другий цикл "за" знаходить ВСІ букви НЕ в четвертині, знаходячи симетричну різницю між набором цих букв, знайдених у виразі, а потім набором, що включає всі необхідні літери. Якщо такі знайдені, то "Квартиріон" додається "+0", за яким пропущена літера та пробіл.

  6. Нарешті, на цьому останньому кроці між кожним символом додається символ ",", після чого символ +/-, а потім Кватерніон розділяється на ці пробіли, потім повертається список сортується, в останню чергу, відповідно до лямбда-функція, визначена як "q" раніше. Коми в вираженні окремо кожну частину кватерніон ( в іншому випадку, ви б отримати що - щось подібне 14i+5j+6kз 4i+5j+6k+1). Нарешті, цей відсортований зараз список об'єднується в рядок, і лише щомісяця будь-яких чисел (люб’язно надавати регулярні вирази) вилучається і, нарешті, щоразу повертається до списку у правильному порядку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.