Belirli Bir Bileşiğin Bayisini Bulun!


12

Meydan okuma

Bir kimyasal formülü verildiğinde, bileşiğin Mr'sini çıktılayın.

Denklem

Bileşikteki her elemanı, bileşikteki adı geçen atomun sayısını gösteren bir sayı takip eder. Bir sayı yoksa, bileşikte bu atomdan sadece bir tane vardır.

Bazı örnekler:

  • Etanol (Cı- 2 , H 6 O) olacaktır C2H6O, iki karbon atomu, R6 hidrojen atomu ve 1 oksijen atomu olduğu yerde
  • Magnezyum hidroksit (MgO 2 H 2 ) olacaktır MgO2H2bir magnezyum atomu, iki oksijen atomu ve iki hidrojen atomu olduğu yerde.

Hiçbir zaman köşeli parantezleri tutmanız gerekmeyeceğini ve her öğenin formülde yalnızca bir kez bulunduğunu unutmayın.

Çoğu insan muhtemelen en rahat hissettikleri düzene bağlı kalırken, sıkı bir sipariş sistemi yoktur. Örneğin, su ya H2Oya olarak verilebilir OH2.

M r

Not: Burada, formül kütlesinin moleküler kütle ile aynı olduğunu varsayalım

M R bir bileşik, moleküler ağırlıktaki toplamıdır atom ağırlıkları molekülde atomu.

Desteklemeniz gereken tek element ve atomik ağırlıkları 1 ondalık basamağa (asil gazlar hariç hidrojen ila kalsiyum) aşağıdaki gibidir. Burada da bulunabilirler

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

Çıkışı her zaman bir ondalık basamağa vermelisiniz.

Örneğin, etanol ( C2H6O) bir erime noktasına sahiptir r arasında 46.0o elementlerin atom ağırlıkları toplamı olarak:

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

Giriş

Yukarıdaki formatta tek bir dize . Denkleme dahil edilen öğelerin gerçek temel semboller olacağını garanti edebilirsiniz.

Verilen bileşiğin gerçekte var olduğu garanti edilmez.

Çıktı

Bileşiğin toplam Mr'si , 1 ondalık basamağa kadar.

kurallar

Erişim elemanına veya kimyasal verilere izin verilmeyen yapı (üzgünüm Mathematica)

Örnekler

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

Kazanan

Bayt cinsinden en kısa kod kazanır.

Bu yazı caird coinheringaahing'in izniyle kabul edildi . (Yayın şimdi silindi)


Nicelleştiricileri ele almamız gerekiyor 2H2Omu , örneğin:?
Bay Xcoder

6
Meraklı için, bu Mathematica çözümü (53 bayt):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min

Yanıtlar:


6

Jöle , 63 bayt

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

Karakter listesini kabul eden ve bir sayı döndüren monadik bir bağlantı.

Çevrimiçi deneyin!

Nasıl?

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

Bu şimdiye kadar gördüğüm en uzun Jelly cevaplarından biri, ama hala şu anda ikinci programın yarısından daha az, çok iyi bir iş!
Gryphon

6

Python 3 ,  1891821616  bayt

Justin Mariner JavaScript (ES6) yanıtı karma kullanarak -14 bayt .

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

Çevrimiçi deneyin!


Aşağıda 182 baytlık bir sürüm var, bunun için açıklamayı bırakacağım - yukarıdaki sadece ağırlıkların sırasını değiştirir int, öğe adını tabandan dönüştürmek için 29kullanır ve tamsayı aralığını sıkıştırmak için farklı temettüler kullanır - bkz. Justin Mariner'in cevabı .

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

Dizeyi kabul eden sve bir sayı döndüren adsız bir işlev .

Çevrimiçi deneyin!

Nasıl?

Girdiyi, söğeleri ve sayılarını kullanarak aşağıdakileri kullanarak bölmek için bir normal ifade kullanır:
re.findall("(\D[a-z]?)(\d*)",s)
\Dtam olarak bir rakam olmayanla [a-z]?eşleşir ve 0 veya 1 küçük harfle eşleşen öğelerle eşleşir. \d*0 veya daha fazla rakamla eşleşir. Parantezler bunları iki gruba ayırır ve bu nedenle findall("...",s)dizelerin tuples'lerinin bir listesini döndürür [(element, number),...].

Numara özü basittir, sap tek şey boş bir dize aracı 1, bu mantıksal ile elde olmasıdır orPython dizeleri Falsey çünkü: int(n or 1).

Öğe dizisine, ilk ve son karakterin ordinallerinin ürününü alarak benzersiz bir sayı verilir (genellikle bunlar S veya C ile aynıdır, ancak Cl, C, Ca ve Na arasında ayrım yapmamız gerekir, bu yüzden sadece birini kullanamayız karakter).

Daha sonra bu sayılar, sonuçta ortaya çıkan modülo alanı araştırılarak bulunan çok daha küçük bir [0,18] aralığını kapsayacak şekilde özetlenir %1135%98%19. Örnek için "Cl"sıra sayılarını sahiptir 67ve 108özellikle, çoklu hangi elde 7736modülo olan, 1135bir 426modülo olan, 98bir 34modülo olan 19olup 15; Bu sayı bir tamsayı listesine dizin için kullanılan - 15 listesinde (0-endeksli) değeri:
[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]
olduğu 35.5, (yukarıda görüldüğü gibi) daha sonra, elemanların sayısı ile çarpılır Cl atom ağırlığı,.

Bu ürünler daha sonra kullanılarak birlikte eklenir sum(...).


Sen bir dahisin ... Beni 350 byte aştı
Bay

4

PHP , 235 bayt

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

Çevrimiçi deneyin!

Bunun yerine aynı Bayt sayısı ile 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])kullanabilirsiniz[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 bayt

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

Jonathan Allan'ın Python cevabından esinlenerek , her bir öğeye benzersiz bir sayı vermeyi ve bu sayıları daha küçük bir aralıkta olmasını sağladığını açıkladı.

Elementler, baz-29 (0-9 ve AS) olarak yorumlanarak benzersiz sayılara dönüştürülmüştür. Daha sonra , benzersizliği korurken %633%35%18değerleri aralığa daralttığını buldum [0, 17].

Test Parçacığı

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, bence senin yolun da beni birkaç bayt kurtaracak!
Jonathan Allan

2

Clojure, 198 194 bayt

Güncelleme: daha iyi fordaha 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))))

Orijinal:

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

Arama tablosunu kodlamanın daha kompakt bir yolu olup olmadığını merak ediyorum.


2

Python 3 , 253 bayt

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

Çevrimiçi deneyin!


1

Mathematica 390 338 329 bayt

Aslında şu anda uyanık olduğum ve aslında tasarladığım kısalmayı kullanarak 9 bayt kaydedildi.

Sürüm 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]&

Açıklama: Tüm büyük harflerin konumunu bulun. Her birine bir nokta koy. Dizeyi her noktaya ayırın. Bu alt dize listesi için aşağıdakileri harflere göre bölün ve rakamlara göre bölün. Harflerle bölünenler için dizeyi sayılara dönüştürün. Rakamlarla bölünmüş olanlar için, her kimyasalın moleküler ağırlığı ile değiştirilir. Molekül ağırlığı ve atom sayısı olan herhangi biri için, bunun yerine onların ürünü ile değiştirin. Toplamı bulurlar.

Versiyon 1:

Eminim bu çok golf olabilir (ya da tamamen yeniden yazılmış). Sadece nasıl yapılacağını bulmak istedim. (Sabah üzerine düşünecek.)

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

Açıklama: Önce dizeyi karakterlere ayırın. Ardından, küçük harf karakterleri ve sayıları büyük harflerine ekleyerek dizinin üzerine katlayın. Ardından, sonunda bir sayı olmayan herhangi bir kimyasal maddeye 1 ekleyin. Sonra dizideki terimlerin iki parçasını yapın - biri tüm sayılarda bölme, diğeri tüm harflerde bölme. İlk önce harfleri molar kütleleriyle değiştirin, ardından bu iki listenin nokta ürününü bulun.


1

Python 3-408 bayt

Bu esas olarak @ovs'un çözümüdür, çünkü 120 baytın üzerinde golf oynadı ... Aşağıdaki ilk çözüme bakın.

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)

Çevrimiçi deneyin!

Python 3 - 550 548 535 bayt (girinti ile kayıp sayısı)

@Cairdcoinheringaahing sayesinde 10 bayt, ovs sayesinde 3 bayt tasarruf etti

Herhangi bir normal ifadeyi kullanmamak ve eğlenceli, eski tarz bir şekilde yapmak için kişisel bir hedefim vardı ... Normal çözümden 350 bayt daha uzun olduğu ortaya çıktı, ancak sadece Python'un standart kütüphanesini kullanıyor ...

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)  

Çevrimiçi deneyin!


Kimse onu golf istekli ise (girinti düzeltmeleri ve diğer hilelerle ...),% 100 iyi karşılanacak, bunu yapmanın daha iyi bir yolu varmış gibi hissedeceksiniz ...


Sen yerini alabilir for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]ilefor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
coinheringaahing Caird

@cairdcoinheringaahing ah, harika ... bir bilgisayara erişimim olduğunda güncelleme
Bay Xcoder

@ovs Çok teşekkürler! Cevapta sizden
alıntı

Python'da, baytları girinti üzerine kaydetmenizi sağlayan yeni satır yerine noktalı virgül kullanabilirsiniz.
Pavel

@Phoenix bir if/for/whilesonraki satırda bir varsa. Girintili her satırda olduğu gibi, baytları bu şekilde kaydedemezsiniz.
ovs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.