Trova il sig. Di un dato composto!


12

Sfida

Data la formula di una sostanza chimica, emette M r del composto.

Equazione

Ogni elemento nel composto è seguito da un numero che indica il numero di detto atomo nel composto. Se non c'è un numero, c'è solo uno di quell'atomo nel composto.

Alcuni esempi sono:

  • L'etanolo (C 2 H 6 O) sarebbe C2H6Odove ci sono due atomi di carbonio, 6 atomi di idrogeno e 1 atomo di ossigeno
  • L'idrossido di magnesio (MgO 2 H 2 ) sarebbe MgO2H2dove c'è un atomo di magnesio, due atomi di ossigeno e due atomi di idrogeno.

Nota che non dovrai mai gestire parentesi e ogni elemento è incluso solo una volta nella formula.

Mentre la maggior parte delle persone probabilmente si atterrà all'ordine con cui si sente più a suo agio, non esiste un sistema di ordinamento rigoroso. Ad esempio, l'acqua può essere data come una H2Oo OH2.

M r

Nota: qui, supponiamo che la massa della formula sia uguale alla massa molecolare

Il M r di un composto, la massa molecolare, è la somma dei pesi atomici degli atomi nella molecola.

Gli unici elementi e i loro pesi atomici al primo decimale che devi sostenere (idrogeno in calcio, esclusi i gas nobili) sono i seguenti. Possono anche essere trovati qui

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

Dovresti sempre dare l'output al primo decimale.

Per esempio, etanolo ( C2H6O) ha una M r di 46.0quanto è la somma dei pesi atomici degli elementi in esso:

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

Ingresso

Una singola stringa nel formato sopra. Puoi garantire che gli elementi inclusi nell'equazione siano veri e propri simboli elementali.

Il composto dato non è garantito per esistere nella realtà.

Produzione

La M r totale del composto, al primo decimale.

Regole

Builtin a cui non sono consentiti elementi di accesso o dati chimici (scusate Mathematica)

Esempi

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

vincente

Vince il codice più breve in byte.

Questo post è stato adottato con il permesso di caher coinheringaahing . (Post ora eliminato)


Dobbiamo gestire quantificatori, come 2H2O:?
Mr. Xcoder,

6
Per i curiosi, questa è la soluzione Mathematica (53 byte):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min

Risposte:


6

Gelatina , 63 byte

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

Un collegamento monadico che accetta un elenco di caratteri e restituisce un numero.

Provalo online!

Come?

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

Questa è una delle risposte Jelly più lunghe che abbia mai visto, ma è ancora meno della metà della durata del programma attualmente al secondo posto, quindi un ottimo lavoro!
Gryphon,

6

Python 3 ,  189188  168 byte

-14 byte usando l'hash dalla risposta JavaScript (ES6) di 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)])

Provalo online!


Di seguito è riportata la versione da 182 byte, lascerò la spiegazione per questo: quanto sopra cambia semplicemente l'ordine dei pesi, usa intper convertire il nome dell'elemento dalla base 29e usa dividendi diversi per comprimere l'intervallo di numeri interi - vedi Giustino La risposta di 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)])

Una funzione senza nome che accetta una stringa se restituisce un numero.

Provalo online!

Come?

Usa una regex per dividere l'input, snegli elementi e nei loro conteggi usando:
re.findall("(\D[a-z]?)(\d*)",s)
\Dcorrisponde esattamente a una non cifra e [a-z]?corrisponde a 0 o 1 lettera minuscola, insieme elementi corrispondenti. \d*corrisponde a 0 o più cifre. Le parentesi rendono questi in due gruppi, e come tale findall("...",s)restituisce una lista di tuple di stringhe, [(element, number),...].

Il numero è semplice da estrarre, l'unica cosa da manico è che un vuoto mezzi stringa 1, essa è ottenuta con una logica ordal stringhe Python sono falsey: int(n or 1).

Alla stringa dell'elemento viene assegnato un numero univoco prendendo il prodotto degli ordinali del suo primo e ultimo carattere (di solito questi sono gli stessi S o C, ma dobbiamo distinguere tra Cl, C, Ca e Na, quindi non possiamo semplicemente usarne uno personaggio).

Questi numeri vengono quindi sottoposti a hash per coprire un intervallo molto più piccolo di [0,18], trovato da una ricerca dello spazio del modulo risultante %1135%98%19. Ad esempio "Cl"ha ordinali 67e 108, che si moltiplicano per dare 7736, quale modulo 1135è 426, quale modulo 98è 34, quale modulo 19è 15; questo numero viene utilizzato per indicizzare in un elenco di numeri interi - il 15 ° (0-indicizzato) valore nell'elenco:
[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, il peso atomico di Cl, che viene quindi moltiplicato per il numero di tali elementi (come si trova sopra).

Questi prodotti vengono quindi aggiunti insieme utilizzando sum(...).


Sei un genio ... Mi ha superato di oltre 350 byte
Mr. Xcoder l'

4

PHP , 235 byte

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

Provalo online!

Invece di 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])te puoi usare [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]con lo stesso conteggio byte


3

JavaScript (ES6), 150 byte

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

Ispirato dalla risposta Python di Jonathan Allan , in cui ha spiegato di dare a ciascun elemento un numero univoco e di eseguire l'hashing di quei numeri in un intervallo più piccolo.

Gli elementi sono stati trasformati in numeri univoci interpretandoli come base-29 (0-9 e AS). Ho quindi scoperto che %633%35%18restringe i valori fino all'intervallo [0, 17]mantenendo l'unicità.

Test snippet

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>


Oh, penso che la tua strada mi salverebbe anche qualche byte!
Jonathan Allan,

2

Clojure, 198 194 byte

Aggiornamento: meglio fordi 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))))

Originale:

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

Mi chiedo se esiste un modo più compatto per codificare la tabella di ricerca.


2

Python 3 , 253 byte

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

Provalo online!


1

Mathematica, 390 338 329 byte

Salvataggio di 9 byte grazie al fatto di essere effettivamente sveglio ora e di utilizzare effettivamente l'accorciamento che intendevo.

Versione 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]&

Spiegazione: trovare la posizione di tutti i caratteri maiuscoli. Metti un punto prima di ciascuno. Dividi la stringa ad ogni punto. Per questo elenco di sottostringhe, procedere come segue suddividendolo in base alle lettere e dividerlo in base alle cifre. Per quelli divisi per lettere converti stringa in numeri. Per quelli divisi per cifre sostituire ogni sostanza chimica con il suo peso molecolare. Per chiunque abbia un peso molecolare e un numero di atomi sostituirlo con il prodotto di essi. Trovano il totale.

Versione 1:

Sono sicuro che questo può essere un sacco di golf (o semplicemente riscritto completamente). Volevo solo capire come farlo. (Rifletterà su di esso al mattino.)

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

Spiegazione: Prima dividere la stringa in caratteri. Quindi ripiegare l'array unendo caratteri minuscoli e numeri al loro capitale. Quindi aggiungi un 1 a qualsiasi sostanza chimica senza un numero alla fine. Quindi esegui due divisioni dei termini nella matrice: una suddivisione in tutti i numeri e una suddivisione in tutte le lettere. Per prima cosa sostituisci le lettere con le loro masse molari, quindi trova il prodotto punto di queste due liste.


1

Python 3 - 408 byte

Questa è principalmente la soluzione di @ovs, dal momento che l'ha ridotta di oltre 120 byte ... Vedi la soluzione iniziale di seguito.

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)

Provalo online!

Python 3 - 550 548 535 byte (perso il conteggio con rientro)

Salvato 10 byte grazie a @cairdcoinheringaahing e 3 salvati grazie a ovs

Avevo un obiettivo personale di non usare alcun regex e farlo nel modo divertente della vecchia scuola ... Si è rivelato essere 350 byte più lungo della soluzione regex, ma utilizza solo la libreria standard di 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)  

Provalo online!


Se qualcuno è disposto a giocare a golf (con correzioni di rientro e altri trucchi ...), sarà accolto al 100%, sentendo che c'è un modo migliore per farlo ...


Puoi sostituirlo for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]confor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
caird coinheringaahing l'

@cairdcoinheringaahing ah, fantastico ... aggiornamento quando ho accesso a un computer
Mr. Xcoder,

@ovs Grazie mille! Ti
ho

In Python, puoi usare un punto e virgola al posto di una nuova riga, che ti consente di salvare byte sul rientro.
Pavel,

@Phoenix non se c'è un if/for/while nella riga successiva. Poiché questo è il caso di ogni riga rientrata, non è possibile salvare byte in questo modo.
Ovs,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.