Найти мистера данного соединения!

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) имеет М р о , 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

выигрыш

Самый короткий код в байтах побеждает.

Этот пост был принят с разрешения Кэрда . (Сообщение удалено)

Бета распад
источник
Нужно ли нам обращаться кванторов, таких как: 2H2O?
г-н Xcoder
6
Для любопытных, это решение Mathematica (53 байта):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Мин

Ответы:

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
Джонатан Аллан
источник
Это один из самых длинных ответов желе, которые я когда-либо видел, но он все еще составляет менее половины длины программы, которая в настоящее время занимает второе место, так что хорошая работа!
Грифон
6

Python 3 ,  189 182  168 байт

-14 байт, используя хэш из ответа Джастина Маринера JavaScript (ES6) .

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),...].

Количество просто в экстракт, единственным , что ручка является то , что пустая строка означает 1, это достигается с логическим , orпоскольку строками Python являются falsey: 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 , где он объяснил, как дать каждому элементу уникальное число и хэшировать эти числа, чтобы они находились в меньшем диапазоне.

Элементы были превращены в уникальные числа, интерпретируя их как base-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]*)"%))

Мне интересно, есть ли более компактный способ кодирования справочной таблицы.

NikoNyrh
источник
2

Python 3 , 253 байта

def m(f,j=0):
 b=j+1
 while'`'<f[b:]<'{':b+=1
 c=b
 while'.'<f[c:]<':':c+=1
 return[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]['Li Be Na Ca Mg Al Si Cl P S K H B C N O F'.split().index(f[j:b])]*int(f[b:c]or 1)+(f[c:]>' 'and m(f,c))

Попробуйте онлайн!

овс
источник
1

Mathematica, 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%, так как есть лучший способ сделать это ...

Мистер Xcoder
источник
Вы можете заменить 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на следующей строке. Так как это имеет место в каждой строке с отступом, вы не можете сохранить байты этим.
овс