Trouvez le Mr d'un composé donné!

12

Défi

Étant donné la formule d'un produit chimique, produire le M r du composé.

Équation

Chaque élément du composé est suivi d'un nombre qui indique le nombre dudit atome dans le composé. S'il n'y a pas de nombre, il n'y a qu'un seul de cet atome dans le composé.

Quelques exemples sont:

  • L'éthanol (C 2 H 6 O) serait là C2H6Ooù il y a deux atomes de carbone, 6 atomes d'hydrogène et 1 atome d'oxygène
  • L'hydroxyde de magnésium (MgO 2 H 2 ) serait là MgO2H2où il y a un atome de magnésium, deux atomes d'oxygène et deux atomes d'hydrogène.

Notez que vous n'aurez jamais à gérer les crochets et que chaque élément n'est inclus qu'une seule fois dans la formule.

Alors que la plupart des gens respecteront probablement la commande avec laquelle ils se sentent le plus à l'aise, il n'y a pas de système de commande strict. Par exemple, l'eau peut être donnée sous forme de H2Oou OH2.

M r

Remarque: ici, supposons que la masse de la formule est la même que la masse moléculaire

Le M r d'un composé, la masse moléculaire, est la somme des poids atomiques des atomes dans la molécule.

Les seuls éléments et leurs poids atomiques à 1 décimale que vous devez supporter (l'hydrogène au calcium, à l'exclusion des gaz nobles) sont les suivants. Ils peuvent également être trouvés ici

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

Vous devez toujours attribuer la sortie à une décimale.

Par exemple, de l' éthanol ( C2H6O) a un M r de 46.0telle qu'elle correspond à la somme des poids atomiques des éléments qu'elle contient :

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

Contribution

Une seule chaîne dans le format ci-dessus. Vous pouvez garantir que les éléments inclus dans l'équation seront de véritables symboles élémentaires.

Le composé donné n'est pas garanti d'exister dans la réalité.

Production

Le total M r du composé, à 1 décimale près.

Règles

Les buildins qui accèdent à un élément ou à des données chimiques sont interdits (désolé Mathematica)

Exemples

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

Gagnant

Le code le plus court en octets gagne.

Ce poste a été adopté avec la permission de caird coinheringaahing . (Message maintenant supprimé)

Beta Decay
la source
Faut-il gérer des quantificateurs, tels que 2H2O:?
M. Xcoder
6
Pour les curieux, NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
voici

Réponses:

6

Gelée , 63 octets

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

Un lien monadique acceptant une liste de caractères et renvoyant un numéro.

Essayez-le en ligne!

Comment?

ḟØ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
Jonathan Allan
la source
C'est l'une des réponses Jelly les plus longues que j'ai jamais vues, mais c'est toujours moins de la moitié de la durée du programme actuellement en deuxième position, donc bon travail!
Gryphon
6

Python 3 ,  189 182 182  168 octets

-14 octets en utilisant le hachage de la réponse JavaScript (ES6) de 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)])

Essayez-le en ligne!


Ci-dessous est la version de 182 octets, je vais laisser l'explication pour celle-ci - ce qui précède modifie simplement l'ordre des poids, utilise intpour convertir le nom de l'élément à partir de la base 29et utilise différents dividendes pour compresser la plage d'entiers - voir Justin Réponse 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)])

Une fonction sans nom acceptant une chaîne set renvoyant un nombre.

Essayez-le en ligne!

Comment?

Utilise une expression régulière pour diviser l'entrée, sen les éléments et leurs
re.findall("(\D[a-z]?)(\d*)",s)
\Dnombres en utilisant: correspond exactement à un non-chiffre et [a-z]?correspond à 0 ou 1 lettre minuscule, ensemble les éléments correspondants. \d*correspond à 0 ou plusieurs chiffres. Les parenthèses font ces deux groupes, et en tant que tel findall("...",s)retourne une liste de tuples de chaînes, [(element, number),...].

Le nombre est simple à extraire, la seule chose à poignée est qu'un moyen de chaîne vide 1, ceci est réalisé avec une logique orpuisque les chaînes Python sont Falsey: int(n or 1).

La chaîne d'élément reçoit un numéro unique en prenant le produit des ordinaux de son premier et dernier caractère (généralement ce sont les mêmes, par exemple S ou C, mais nous devons faire la différence entre Cl, C, Ca et Na, donc nous ne pouvons pas simplement en utiliser un personnage).

Ces nombres sont ensuite hachés pour couvrir une plage beaucoup plus petite de [0,18], trouvée par une recherche de l'espace modulo résultant %1135%98%19. Par exemple, "Cl"a des ordinaux 67et 108, qui se multiplient pour donner 7736, ce qui 1135est modulo 426, quel modulo 98est 34, quel modulo 19est 15; ce nombre est utilisé pour indexer dans une liste d'entiers - la 15e valeur (indexée 0) dans la liste:
[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]
is 35.5, le poids atomique de Cl, qui est ensuite multiplié par le nombre de ces éléments (comme indiqué ci-dessus).

Ces produits sont ensuite additionnés à l'aide de sum(...).

Jonathan Allan
la source
Vous êtes un génie ... m'a dépassé de plus de 350 octets
M. Xcoder
4

PHP , 235 octets

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

Essayez-le en ligne!

Au lieu 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])vous pouvez utiliser [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]avec le même nombre d'octets

Jörg Hülsermann
la source
3

JavaScript (ES6), 150 octets

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

Inspiré par la réponse Python de Jonathan Allan , où il a expliqué donner à chaque élément un numéro unique et hacher ces nombres pour qu'ils soient dans une plage plus petite.

Les éléments ont été transformés en nombres uniques en les interprétant comme base-29 (0-9 et AS). J'ai ensuite constaté que %633%35%18rétrécit les valeurs jusqu'à la plage de [0, 17]tout en conservant l'unicité.

Extrait de test

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>

Justin Mariner
la source
Oh, je pense que votre chemin me sauverait aussi quelques octets!
Jonathan Allan
2

Clojure, 198 194 octets

Mise à jour: mieux 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]*)"%))

Je me demande s'il existe un moyen plus compact d'encoder la table de recherche.

NikoNyrh
la source
2

Python 3 , 253 octets

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

Essayez-le en ligne!

ovs
la source
1

Mathematica, 390 338 329 octets

9 octets enregistrés en raison du fait que je suis actuellement réveillé et que j'utilise le raccourcissement que je voulais.

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

Explication: recherchez la position de tous les caractères majuscules. Mettez un point devant chacun. Divisez la chaîne à chaque point. Pour cette liste de sous-chaînes, procédez comme suit: fractionnez-le en fonction des lettres et divisez-le en fonction des chiffres. Pour ceux divisés par des lettres, convertissez la chaîne en chiffres. Pour ceux divisés par des chiffres, remplacez chaque produit chimique par son poids moléculaire. Pour ceux qui ont un poids moléculaire et un nombre d'atomes, remplacez-le par le produit d'eux. Ils trouvent le total.

Version 1:

Je suis sûr que cela peut être beaucoup de golf (ou juste complètement réécrit). Je voulais juste comprendre comment le faire. (Y réfléchira le matin.)

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

Explication: Commencez par diviser la chaîne en caractères. Repliez ensuite le tableau en joignant les caractères et les chiffres en minuscules à leur capitale. Ensuite, ajoutez un 1 à n'importe quel produit chimique sans numéro à la fin. Effectuez ensuite deux divisions des termes dans le tableau - une division à tous les nombres et une séparation à toutes les lettres. Pour le premier remplacer les lettres par leurs masses molaires puis trouver le produit scalaire de ces deux listes.

Ian Miller
la source
1

Python 3 - 408 octets

Il s'agit principalement de la solution de @ovs, car il l'a analysée de plus de 120 octets ... Voir la solution initiale ci-dessous.

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)

Essayez-le en ligne!

Python 3 - 550 548 535 octets (perdu le compte avec indentation)

10 octets enregistrés grâce à @cairdcoinheringaahing et 3 enregistrés grâce à ovs

J'avais un objectif personnel de ne pas utiliser d'expressions régulières, et de le faire de manière amusante et à l'ancienne ... Cela s'est avéré être 350 octets plus long que la solution d'expressions régulières, mais il n'utilise que la bibliothèque standard de 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)  

Essayez-le en ligne!


Si quelqu'un est prêt à jouer au golf (avec des corrections d'indentation et d'autres astuces ...), il sera 100% bien reçu, se sentant comme s'il y avait une meilleure façon de le faire ...

M. Xcoder
la source
Vous pouvez remplacer for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]parfor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
caird coinheringaahing
@cairdcoinheringaahing ah, super ... mise à jour quand j'ai accès à un ordinateur
M. Xcoder
@ovs Merci beaucoup! Vous a crédité la réponse
M. Xcoder
En Python, vous pouvez utiliser un point-virgule à la place d'une nouvelle ligne, ce qui vous permet d'économiser des octets lors de l'indentation.
Pavel
@Phoenix pas s'il y a un if/for/whilesur la ligne suivante. Comme c'est le cas sur chaque ligne en retrait, vous ne pouvez pas enregistrer d'octets par cela.
2017