Знайдіть містера даної сполуки!


12

Виклик

Враховуючи формулу хімічного речовини, виведіть M r сполуки.

Рівняння

Кожен елемент сполуки супроводжується числом, яке позначає кількість зазначеного атома в сполуці. Якщо немає числа, у складі сполуки є лише один з цього атома.

Деякі приклади:

  • Етанол (C 2 H 6 O) був би C2H6Oтам, де є два атоми вуглецю, 6 атомів водню та 1 атом кисню
  • Гідроксид магнію (MgO 2 H 2 ) був би MgO2H2там, де є один атом магнію, два атоми кисню та два атоми водню.

Зауважте, що вам ніколи не доведеться обробляти дужки, і кожен елемент включається лише один раз у формулу.

Хоча більшість людей, ймовірно, дотримуватимуться порядку, в якому вони відчувають себе найбільш комфортно, немає суворої системи замовлення. Наприклад, воду можна подавати у вигляді H2Oабо OH2.

М р

Примітка. Тут припустимо, маса формули така ж, як молекулярна маса

M r сполуки, молекулярна маса, - це сума атомних ваг атомів у молекулі.

Єдині елементи та їх атомна вага до 1 десяткового знаку, який ви повинні підтримувати (водень до кальцію, не включаючи благородні гази), полягають у наступному. Їх також можна знайти тут

H  - 1.0      Li - 6.9      Be - 9.0
B  - 10.8     C  - 12.0     N  - 14.0
O  - 16.0     F  - 19.0     Na - 23.0
Mg - 24.3     Al - 27.0     Si - 28.1
P  - 31.0     S  - 32.1     Cl - 35.5
K  - 39.1     Ca - 40.1

Ви завжди повинні давати результат в одне десяткове місце.

Наприклад, етанол ( C2H6O) має M р про , 46.0як це сума атомних ваг елементів в ньому:

12.0 + 12.0 + 1.0 + 1.0 + 1.0 + 1.0 + 1.0 + 1.0 + 16.0
(2*C + 6*H + 1*O)

Вхідні дані

Одинокий рядок у наведеному вище форматі. Ви можете гарантувати, що елементи, що входять до рівняння, будуть фактичними елементарними символами.

Даний склад не гарантовано існує в реальності.

Вихідні дані

Загальна M r сполуки, до 1 десяткового знака.

Правила

Вбудовані елементи з елементом доступу або хімічними даними заборонені (вибачте, Mathematica)

Приклади

Input > Output
CaCO3 > 100.1
H2SO4 > 98.1
SF6 > 146.1
C100H202O53 > 2250.0

Перемога

Виграє найкоротший код у байтах.

Ця посада була прийнята з дозволу у співрозмовництві caird . (Публікація видалена)


Чи потрібно обробляти квантори, такі як 2H2O:?
Містер Xcoder

6
Для допитливих це рішення Mathematica (53 байти):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min

Відповіді:


6

Желе , 63 байти

ḟØDOP%⁽¡ṛị“ÇṚÆ’BH+“Ḳ"ɦṀ⁷6<s¡_-¦y⁼Ḟ¡¡FPɓ‘¤÷5
fØDVȯ1×Ç
Œs>œṗ⁸ḊÇ€S

Монадійне посилання, що приймає список символів та повертає число.

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

Як?

ḟØDOP%⁽¡ṛị“ÇṚÆ’BH+“Ḳ"ɦṀ⁷6<s¡_-¦y⁼Ḟ¡¡FPɓ‘¤÷5 - Link 1, Atomic weight: list of characters
                                            -                              e.g. "Cl23"
 ØD                                         - digit yield = "0123456789"
ḟ                                           - filter discard                      "Cl"
   O                                        - cast to ordinals                [67,108]
    P                                       - product                            7236
      ⁽¡ṛ                                   - base 250 literal = 1223
     %                                      - modulo                             1121
                                        ¤   - nilad followed by link(s) as a nilad:
          “ÇṚÆ’                             -   base 250 literal  = 983264
               B                            -   convert to binary = [    1,    1,     1,     1,   0,  0,  0,   0, 0,  0,  0, 0,     1,     1,     1, 0, 0,  0,  0,   0]
                H                           -   halve             = [  0.5,  0.5,   0.5,   0.5,   0,  0,  0,   0, 0,  0,  0, 0,   0.5,   0.5,   0.5, 0, 0,  0,  0,   0]
                  “Ḳ"ɦṀ⁷6<s¡_-¦y⁼Ḟ¡¡FPɓ‘    -   code-page indexes = [177  , 34  , 160  , 200  , 135, 54, 60, 115, 0, 95, 45, 5, 121  , 140  , 195  , 0, 0, 70, 80, 155]
                 +                          -   addition          = [177.5, 34.5, 160.5, 200.5, 135, 54, 60, 115, 0, 95, 45, 5, 121.5, 140.5, 195.5, 0, 0, 70, 80, 155]
         ị                                  - index into (1-indexed and modular)
                                            -    ...20 items so e.g. 1121%20=1 so 177.5
                                         ÷5 - divide by 5                          35.5

fØDVȯ1×Ç - Link 2: Total weight of multiple of atoms: list of characters   e.g. "Cl23"
 ØD      - digit yield = "0123456789"
f        - filter keep                                                            "23"
   V     - evaluate as Jelly code                                                  23
    ȯ1   - logical or with one (no digits yields an empty string which evaluates to zero)
       Ç - call last link (1) as a monad (get the atomic weight)                   35.5
      ×  - multiply                                                               816.5

Œs>œṗ⁸ḊÇ€S - Main link: list of characters                             e.g. "C24HCl23"
Œs         - swap case                                                      "c24hcL23"
  >        - greater than? (vectorises)                                      10011000
     ⁸     - chain's left argument                                          "C24HCl23"
   œṗ      - partition at truthy indexes                          ["","C24","H","Cl23"]
      Ḋ    - dequeue                                                 ["C24","H","Cl23"]
       Ç€  - call last link (2) as a monad for €ach                  [  288,  1,  816.5]
         S - sum                                                                 1105.5

Це одна з найдовших відповідей Jelly, яку я коли-небудь бачив, але це все ще менше половини тривалості програми, яка зараз перебуває на другій, настільки хороша робота!
Грифон

6

Пітон 3 ,  189 182  168 байт

-14 байт, використовуючи хеш відповіді JavaScript (ES6) Justin Mariner .

import re
lambda s:sum([[9,35.5,39.1,24.3,28.1,14,16,31,40.1,23,32.1,10.8,12,27,6.9,19,0,1][int(a,29)%633%35%18]*int(n or 1)for a,n in re.findall("(\D[a-z]?)(\d*)",s)])

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


Нижче наведено 182-байтну версію, я залишу пояснення для цього - вищезгадане просто змінює порядок зважування, використовує intдля перетворення назви елемента з бази 29та використовує різні дивіденди для стиснення діапазону цілих чисел вниз - див. Джастін Відповідь Марінера .

import re
lambda s:sum([[16,31,40.1,32.1,0,24.3,12,39.1,28.1,19,0,9,10.8,23,27,35.5,6.9,14,1][ord(a[0])*ord(a[-1])%1135%98%19]*int(n or 1)for a,n in re.findall("(\D[a-z]?)(\d*)",s)])

Безіменна функція, що приймає рядок sта повертає число.

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

Як?

Використовує регулярний вираз, щоб розділити вхідні дані sна елементи та їх кількість, використовуючи:
re.findall("(\D[a-z]?)(\d*)",s)
\Dвідповідає точно одній нецифровій і [a-z]?відповідає 0 або 1 малої літери, разом збігаючи елементи. \d*відповідає 0 або більше цифр. Дужки зробити їх на дві групи, і як такий findall("...",s)повертає список кортежів рядків, [(element, number),...].

orЦифру витягнути просто, єдине, що потрібно обробити, це те, що порожній рядок означає 1, це досягається логічно, оскільки струни Python є фальсифікованими:int(n or 1) .

Рядок елементів присвоюється унікальному номеру, беручи добуток розпоряджень першого та останнього символів (зазвичай вони однакові, наприклад, S або C, але нам потрібно розмежовувати Cl, C, Ca і Na, тому ми не можемо просто використовувати один персонаж).

Ці числа потім хеширують, щоб охопити набагато менший діапазон [0,18], знайдений шляхом пошуку модульного простору, що призводить до %1135%98%19. Наприклад "Cl"є порядкові 67і 108, що багаторазово давати 7736, що, по модулю 1135є 426, по модулю , який 98є 34, по модулю якого 19є 15; це число використовується для індексації до списку цілих чисел - 15-го (0-індексованого) значення у списку:
[16,31,40.1,32.1,0,24.3,12,39.1,28.1,19,0,9,10.8,23,27,35.5,6.9,14,1]
це 35.5атомна маса Cl, яка потім множиться на кількість таких елементів (як знайдено вище).

Потім ці продукти додаються разом, використовуючи sum(...).


Ви геній ... Перевершив мене понад 350 байтів
містер Xcoder

4

PHP , 235 байт

preg_match_all("#([A-Z][a-z]?)(\d*)#",$argn,$m);foreach($m[1]as$v)$s+=array_combine([H,Li,Be,B,C,N,O,F,Na,Mg,Al,Si,P,S,Cl,K,Ca],[1,6.9,9,10.8,12,14,16,19,23,24.3,27,28.1,31,32.1,35.5,39.1,40.1])[$v]*($m[2][+$k++]?:1);printf("%.1f",$s);

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

Замість array_combine([H,Li,Be,B,C,N,O,F,Na,Mg,Al,Si,P,S,Cl,K,Ca],[1,6.9,9,10.8,12,14,16,19,23,24.3,27,28.1,31,32.1,35.5,39.1,40.1]) ви можете використовувати [H=>1,Li=>6.9,Be=>9,B=>10.8,C=>12,N=>14,O=>16,F=>19,Na=>23,Mg=>24.3,Al=>27,Si=>28.1,P=>31,S=>32.1,Cl=>35.5,K=>39.1,Ca=>40.1]з тим самим числом байтів


3

JavaScript (ES6), 150 байт

c=>c.replace(/(\D[a-z]?)(\d+)?/g,(_,e,n=1)=>s+=[9,35.5,39.1,24.3,28.1,14,16,31,40.1,23,32.1,10.8,12,27,6.9,19,0,1][parseInt(e,29)%633%35%18]*n,s=0)&&s

Натхненний Джонатана Аллана Python , де він пояснив надання кожному елементу унікального числа та хеширование цих чисел у меншому діапазоні.

Елементи були складені в унікальні числа, інтерпретуючи їх як бази-29 (0-9 та AS). Потім я це виявив%633%35%18 звужує значення до діапазону [0, 17], зберігаючи унікальність.

Тест-фрагмент

f=
c=>c.replace(/(\D[a-z]?)(\d+)?/g,(_,e,n=1)=>s+=[9,35.5,39.1,24.3,28.1,14,16,31,40.1,23,32.1,10.8,12,27,6.9,19,0,1][parseInt(e,29)%633%35%18]*n,s=0)&&s
Input: <input oninput="O.value=f(this.value)"><br>
Result: <input id="O" disabled>


О, я думаю, ваш шлях також врятував би мені кілька байтів!
Джонатан Аллан

2

Clojure, 198 194 байт

Оновлення: краще, forніж ніж reduce.

#(apply +(for[[_ e n](re-seq #"([A-Z][a-z]?)([0-9]*)"%)](*(if(=""n)1(Integer. n))({"H"1"B"10.8"O"16"Mg"24.3"P"31"K"39.1"Li"6.9"C"12"F"19"Al"2"S"32.1"Ca"40.1"Be"9"N"14"Na"23"Si"28.1"Cl"35.5}e))))

Оригінал:

#(reduce(fn[r[_ e n]](+(*(if(=""n)1(Integer. n))({"H"1"B"10.8"O"16"Mg"24.3"P"31"K"39.1"Li"6.9"C"12"F"19"Al"2"S"32.1"Ca"40.1"Be"9"N"14"Na"23"Si"28.1"Cl"35.5}e))r))0(re-seq #"([A-Z][a-z]?)([0-9]*)"%))

Мені цікаво, чи існує більш компактний спосіб кодування таблиці пошуку.



1

Математика, 390 338 329 байт

Збережено 9 байт через те, що насправді не прокинувся і фактично використовував скорочення, яке я призначив.

Версія 2.1:

S=StringSplit;Total[Flatten@{ToExpression@S[#,LetterCharacter],S[#,DigitCharacter]}&/@S[StringInsert[#,".",First/@StringPosition[#,x_/;UpperCaseQ[x]]],"."]/.{"H"->1,"Li"->3,"Be"->9,"B"->10.8,"C"->12,"N"->14,"O"->16,"F"->19,"Na"->23,"Mg"->24.3,"Al"->27,"Si"->28.1,"P"->31,"S"->32.1,"Cl"->35.5,"K"->39.1,"Ca"->40.1}/.{a_,b_}->a*b]&

Пояснення: Знайдіть положення всіх великих літер. Поставте крапку перед кожною. Розділіть рядок на кожну крапку. Для цього списку підрядів виконайте наступне розділення його на літери та розділення на основі цифр. Для розділених на літери перетворять рядок у числа. Для розділених цифрами замініть кожну хімічну речовину на її молекулярну масу. Для будь-якого з молекулярною масою та кількістю атомів замініть його на продукт з них. Вони знаходять загальну суму.

Версія 1:

Я впевнений, що це можуть бути ділянки для гольфу (або просто повністю переписані). Я просто хотів розібратися, як це зробити. (Подумає про це вранці.)

F=Flatten;d=DigitCharacter;S=StringSplit;Total@Apply[Times,#,2]&@(Transpose[{F@S[#,d],ToExpression@F@S[#,LetterCharacter]}]&@(#<>If[StringEndsQ[#,d],"","1"]&/@Fold[If[UpperCaseQ[#2],Append[#,#2],F@{Drop[#,-1],Last[#]<>#2}]&,{},StringPartition[#,1]]))/.{"H"->1,"Li"->3,"Be"->9,"B"->10.8,"C"->12,"N"->14,"O"->16,"F"->19,"Na"->23,"Mg"->24.3,"Al"->27,"Si"->28.1,"P"->31,"S"->32.1,"Cl"->35.5,"K"->39.1,"Ca"->40.1}&

Пояснення: Спочатку розділіть рядок на символи. Потім складіть масив, з'єднавши малі символи та цифри назад до їх великої літери. Далі додайте 1 до будь-якого хімічного речовини без цифри на кінці. Потім зробіть два розбиття доданків у масиві - один розбиття на всі числа і один розбиття на всі літери. Для початку замініть літери на їх молярні маси, потім знайдіть крапковий добуток цих двох списків.


1

Python 3 - 408 байт

Це в основному рішення @ovs, оскільки він переграв його на понад 120 байт ... Дивіться початкове рішення нижче.

e='Li Be Na Ca Mg Al Si Cl P S K H B C N O F'.split()
f,g=input(),[]
x=r=0
for i in e:
 if i in f:g+=[(r,eval('6.9 9 23 40.1 24.3 27 28.1 35.5 31 32.1 39.1 1 10.8 12 14 16 19'.split()[e.index(i)]))];f=f.replace(i,' %d- '%r);r+=1
h=f.split()
for c,d in zip(h,h[1:]):
 s=c.find('-')
 if-1<s:
  if'-'in d:
   for y in g:x+=y[1]*(str(y[0])==c[:s])
  else:
   for y in g:x+=y[1]*int(d)*(str(y[0])==c[:s])
print(x)

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

Python 3 - 550 548 535 байт (втрачено рахунок з відступом)

Збережено 10 байт завдяки @cairdcoinheringaahing та 3 збережених завдяки ovs

У мене була особиста мета - не використовувати жодних регулярних виразів, і робити це весело, старошкільним способом ... Виявилося, це на 350 байт довше, ніж рішення для регулярних виразів, але він використовує лише стандартну бібліотеку Python ...

a='Li6.9 Be9. Na23. Ca40.1 Mg24.3 Al27. Si28.1 Cl35.5 P-31. S-32.1 K-39.1 H-1. B-10.8 C-12. N-14. O-16. F-19.'.split()
e,m,f,g,r=[x[:1+(x[1]>'-')]for x in a],[x[2:]for x in a],input(),[],0
for i in e:
 if i in f:g.append((r,float(m[e.index(i)])));f=f.replace(i,' '+str(r)+'- ');r+=1;
h,x=f.split(),0
for i in range(len(h)):
 if '-'in h[i]:
    if '-'in h[i+1]:
     for y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
    else:
        for y in g:
         if str(y[0])==h[i][:h[i].index('-')]:x+=(y[1])*int(h[i+1])
 else:1
print(x)  

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


Якщо хтось бажає пограти в нього (з виправленнями відступів та іншими хитрощами ...), він буде на 100% добре сприйнятий, відчуваючи, що є кращий спосіб зробити це ...


Ви можете замінити for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]наfor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
caird coinheringaahing

@cairdcoinheringaahing ах, чудово ... оновлення, коли у мене є доступ до комп'ютера
містер Xcoder

@ovs Дякую велике! Подячив вас у відповідь
містер Xcoder

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

@Phoenix немає, якщо в if/for/whileнаступному рядку є Оскільки це відбувається у кожному відступному рядку, ви не можете зберегти байти за допомогою цього.
ов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.