Encontre o Sr. de um determinado composto!


12

Desafio

Dada a fórmula de um produto químico, produza o M r do composto.

Equação

Cada elemento do composto é seguido por um número que indica o número do referido átomo no composto. Se não houver um número, existe apenas um desse átomo no composto.

Alguns exemplos são:

  • O etanol (C 2 H 6 O) seria C2H6Oonde existem dois átomos de carbono, 6 átomos de hidrogênio e 1 átomo de oxigênio
  • Hidróxido de magnésio (MgO 2 H 2 ) seria MgO2H2onde existe um átomo de magnésio, dois átomos de oxigênio e dois átomos de hidrogênio.

Observe que você nunca precisará lidar com colchetes e cada elemento é incluído apenas uma vez na fórmula.

Embora a maioria das pessoas provavelmente atenha à ordem com a qual se sente mais confortável, não existe um sistema de pedidos rigoroso. Por exemplo, a água pode ser dada como H2Oou OH2.

M r

Nota: Aqui, suponha que a massa da fórmula seja igual à massa molecular

O Mr de um composto, a massa molecular, é a soma dos pesos atômicos dos átomos na molécula.

Os únicos elementos e seus pesos atômicos com uma casa decimal que você precisa suportar (hidrogênio e cálcio, sem incluir gases nobres) são os seguintes. Eles também podem ser encontrados aqui

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

Você sempre deve fornecer a saída com uma casa decimal.

Por exemplo, etanol ( C2H6O) tem uma M r de 46.0como é a soma das massas atómicas dos elementos nele:

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

Entrada

Uma única sequência no formato acima. Você pode garantir que os elementos incluídos na equação sejam símbolos elementares reais.

Não é garantido que o composto fornecido exista na realidade.

Resultado

O total Mr do composto, com 1 casa decimal.

Regras

Construções que acessam elementos ou dados químicos não são permitidas (desculpe Mathematica)

Exemplos

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

Ganhando

O código mais curto em bytes vence.

Este post foi adotado com permissão de caird coinheringaahing . (Postagem excluída)


Temos que lidar com quantificadores, como 2H2O:?
Mr. Xcoder

6
Para os curiosos, esta é a solução Mathematica (53 bytes):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min 11/11

Respostas:


6

Geléia , 63 bytes

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

Um link monádico que aceita uma lista de caracteres e retorna um número.

Experimente online!

Quão?

ḟØ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

Esta é uma das respostas mais longas da Jelly que eu já vi, mas ainda é menos da metade da duração do programa atualmente em segundo, trabalho tão bom!
Gryphon

6

Python 3 ,  189188  168 bytes

-14 bytes usando o hash da resposta JavaScript de Justin Mariner (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)])

Experimente online!


Abaixo está a versão de 182 bytes, deixarei a explicação para este - o acima apenas altera a ordem dos pesos, usa intpara converter o nome do elemento da base 29e usa dividendos diferentes para compactar o intervalo de números inteiros - veja Justin Resposta de Mariner .

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

Uma função sem nome que aceita uma sequência se retorna um número.

Experimente online!

Quão?

Usa um regex para dividir a entrada s,, nos elementos e suas contagens usando:
re.findall("(\D[a-z]?)(\d*)",s)
\Dcorresponde exatamente a um não dígito e [a-z]?corresponde a 0 ou 1 letra minúscula, junto a elementos correspondentes. \d*corresponde a 0 ou mais dígitos. Os parênteses os transformam em dois grupos e, como tal, findall("...",s)retorna uma lista de tuplas de strings [(element, number),...].

O número é simples de extrair, a única coisa a alça é que um meio de cordas vazias 1, isto é conseguido com uma lógica ordesde cordas Python são Falsey: int(n or 1).

A cadeia de elementos recebe um número único, obtendo o produto dos ordinais de seu primeiro e último caractere (geralmente são os mesmos, por exemplo, S ou C, mas precisamos diferenciar entre Cl, C, Ca e Na, para que não possamos usar apenas um personagem).

Esses números são então divididos em hash para cobrir um intervalo muito menor de [0,18], encontrado por uma pesquisa no espaço do módulo resultante %1135%98%19. Por exemplo, "Cl"tem ordinais 67e 108, que se multiplicam para dar 7736, qual 1135é o módulo 426, qual 98é o módulo 34, qual 19é o módulo 15; esse número é usado para indexar em uma lista de números inteiros - o 15º valor (indexado em 0) da lista:
[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.5o peso atômico de Cl, que é então multiplicado pelo número de tais elementos (como encontrado acima).

Esses produtos são então adicionados usando sum(...).


Você é um gênio ... me Outgolfed por mais de 350 bytes
Mr. Xcoder

4

PHP , 235 bytes

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

Experimente online!

Em vez de 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])você pode usar [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]com a mesma contagem de bytes


3

JavaScript (ES6), 150 bytes

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

Inspirado na resposta Python de Jonathan Allan , onde ele explicou dar a cada elemento um número único e colocar esses números em um intervalo menor.

Os elementos foram transformados em números únicos, interpretando-os como base 29 (0-9 e AS). Descobri então que %633%35%18reduz os valores até o intervalo [0, 17], mantendo a exclusividade.

Snippet de teste

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>


Ah, acho que seu caminho me salvaria alguns bytes também!
Jonathan Allan

2

Clojure, 198 194 bytes

Atualização: melhor forque 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))))

Original:

#(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]*)"%))

Gostaria de saber se existe uma maneira mais compacta de codificar a tabela de consulta.


2

Python 3 , 253 bytes

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

Experimente online!


1

Mathematica, 390 338 329 Bytes

Economizei 9 bytes devido a estar realmente acordado agora e a usar o encurtamento pretendido.

Versão 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]&

Explicação: Encontre a posição de todos os caracteres maiúsculos. Coloque um ponto antes de cada um. Divida a corda em cada ponto. Para esta lista de substrings, faça a seguinte divisão com base em letras e em dígitos. Para os que são divididos por letras, converta a sequência em números. Para os que são divididos por dígitos, substitua cada produto químico pelo seu peso molecular. Para aqueles com peso molecular e contagem de átomos, substitua-o pelo produto deles. Eles encontram o total.

Versão 1:

Tenho certeza de que isso pode ser um lote de golfe (ou apenas completamente reescrito). Eu só queria descobrir como fazê-lo. (Refletirá sobre isso de manhã.)

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

Explicação: Primeiro divida a sequência em caracteres. Em seguida, dobre a matriz juntando caracteres minúsculos e números de volta ao seu capital. Em seguida, acrescente 1 a qualquer produto químico sem um número no final. Em seguida, faça duas divisões dos termos na matriz - uma dividida em todos os números e uma dividida em todas as letras. Na primeira, substitua as letras pelas massas molares e encontre o produto escalar dessas duas listas.


1

Python 3-408 bytes

Esta é principalmente a solução do @ovs, já que ele reduziu em mais de 120 bytes ... Veja a solução inicial abaixo.

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)

Experimente online!

Python 3 - 550 548 535 bytes (perdeu a contagem com recuo)

Guardou 10 bytes graças a @cairdcoinheringaahing e 3 guardou graças a ovs

Eu tinha um objetivo pessoal de não usar nenhum regex e fazê-lo da maneira divertida e antiga ... Acabou sendo 350 bytes a mais que a solução regex, mas ele usa apenas a biblioteca padrão do 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)  

Experimente online!


Se alguém quiser jogar golfe (com correções de indentação e outros truques ...), será 100% bem recebido, sentindo que há uma maneira melhor de fazer isso ...


Você pode substituir for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]porfor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
caird coinheringaahing

@cairdcoinheringaahing ah, ótimo ... atualizar quando eu tiver acesso a um computador
Mr. Xcoder

@ovs Muito obrigado! Creditou você na resposta
Mr. Xcoder 12/17/17

No Python, você pode usar um ponto e vírgula no lugar de uma nova linha, o que permite salvar bytes no recuo.
Pavel

@ Phoenix não se houver if/for/whilena próxima linha. Como esse é o caso em todas as linhas recuadas, você não pode salvar bytes com isso.
ovs 12/06
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.