Temukan Tuan Senyawa yang Diberikan!

12

Tantangan

Mengingat formula suatu bahan kimia, hasilkan M r dari senyawa tersebut.

Persamaan

Setiap elemen dalam senyawa diikuti oleh angka yang menunjukkan jumlah atom tersebut dalam senyawa. Jika tidak ada nomor, hanya ada satu atom di dalam senyawa.

Beberapa contoh adalah:

  • Etanol (C 2 H 6 O) akan berada di C2H6Otempat terdapat dua atom karbon, 6 atom hidrogen, dan 1 atom oksigen
  • Magnesium Hidroksida (MgO 2 H 2 ) akan berada di MgO2H2tempat terdapat satu atom magnesium, dua atom oksigen, dan dua atom hidrogen.

Perhatikan bahwa Anda tidak akan pernah harus menangani tanda kurung dan setiap elemen dimasukkan hanya sekali dalam rumus.

Sementara kebanyakan orang mungkin akan tetap pada urutan yang mereka rasa paling nyaman, tidak ada sistem pemesanan yang ketat. Sebagai contoh, air dapat diberikan sebagai salah satu H2Oatau OH2.

M r

Catatan: Di sini, anggap massa rumus sama dengan massa molekul

M r senyawa, massa molekul, adalah jumlah dari berat atom dari atom-atom dalam molekul.

Satu-satunya unsur dan bobot atomnya ke 1 desimal yang harus Anda dukung (hidrogen menjadi kalsium, tidak termasuk gas mulia) adalah sebagai berikut. Mereka juga dapat ditemukan di sini

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

Anda harus selalu memberikan output ke satu tempat desimal.

Sebagai contoh, etanol ( C2H6O) memiliki M r dari 46.0karena merupakan jumlah dari berat atom dari unsur-unsur di dalamnya:

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

Memasukkan

Satu string dalam format di atas. Anda bisa menjamin bahwa elemen yang dimasukkan dalam persamaan akan menjadi simbol elemen yang sebenarnya.

Senyawa yang diberikan tidak dijamin ada dalam kenyataan.

Keluaran

Total M r dari senyawa, ke 1 tempat desimal.

Aturan

Dibangun di mana elemen akses atau data kimia tidak diizinkan (maaf Mathematica)

Contohnya

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

Kemenangan

Kode terpendek dalam byte menang.

Posting ini diadopsi dengan izin dari caird coinheringaahing . (Posting sekarang dihapus)

Peluruhan Beta
sumber
Apakah kita harus menangani bilangan, seperti: 2H2O?
Tn. Xcoder
6
Bagi yang penasaran, ini adalah solusi Mathematica (53 bytes):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min

Jawaban:

6

Jelly , 63 byte

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

Tautan monadik yang menerima daftar karakter dan mengembalikan nomor.

Cobalah online!

Bagaimana?

ḟØ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
sumber
Ini adalah salah satu jawaban Jelly terpanjang yang pernah saya lihat, tetapi masih kurang dari setengah panjang program saat ini di posisi kedua, pekerjaan yang sangat bagus!
Gryphon
6

Python 3 ,  189 182  168 byte

-14 byte dengan menggunakan hash dari jawaban Justin Mariner's 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)])

Cobalah online!


Di bawah ini adalah versi 182 byte, saya akan meninggalkan penjelasan untuk yang ini - yang di atas hanya mengubah urutan bobot, menggunakan intuntuk mengkonversi nama elemen dari basis 29, dan menggunakan dividen yang berbeda untuk mengompresi kisaran bilangan bulat ke bawah - lihat Justin Jawaban 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)])

Fungsi yang tidak disebutkan namanya menerima string s,, dan mengembalikan nomor.

Cobalah online!

Bagaimana?

Menggunakan regex untuk membagi input,, ske dalam elemen dan jumlah mereka menggunakan:
re.findall("(\D[a-z]?)(\d*)",s)
\Dcocok dengan tepat satu non-digit dan [a-z]?cocok dengan 0 atau 1 huruf kecil, bersama-sama dengan elemen yang cocok. \d*cocok dengan 0 atau lebih digit. Tanda kurung membuat ini menjadi dua kelompok, dan dengan demikian findall("...",s)mengembalikan daftar tupel string [(element, number),...],.

Jumlah ini sederhana untuk ekstrak, satu-satunya untuk menangani adalah bahwa sarana string kosong 1, ini dicapai dengan logis orkarena Python string adalah falsey: int(n or 1).

String elemen diberi nomor unik dengan mengambil produk dari ordinals karakter pertama dan terakhirnya (biasanya ini sama misalnya S atau C, tetapi kita perlu membedakan antara Cl, C, Ca, dan Na sehingga kita tidak bisa hanya menggunakan satu karakter).

Angka-angka ini kemudian dipotong untuk mencakup kisaran yang jauh lebih kecil [0,18], ditemukan oleh pencarian ruang modulo yang menghasilkan %1135%98%19. Misalnya "Cl"memiliki ordinals 67dan 108, yang berkembang biak untuk memberi 7736, yang, modulo 1135adalah 426, yang modulo 98adalah 34, yang mana modulo 19adalah 15; angka ini digunakan untuk mengindeks ke dalam daftar bilangan bulat - nilai ke-15 (terindeks-0) dalam daftar:
[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]
adalah 35.5, berat atom Cl, yang kemudian dikalikan dengan jumlah elemen tersebut (seperti yang ditemukan di atas).

Produk-produk ini kemudian ditambahkan bersama menggunakan sum(...).

Jonathan Allan
sumber
Anda seorang jenius ... Mengalahkan saya lebih dari 350 byte
Tn. Xcoder
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);

Cobalah online!

Alih-alih 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])Anda dapat menggunakan [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]dengan jumlah Byte yang sama

Jörg Hülsermann
sumber
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

Terinspirasi oleh jawaban Python Jonathan Allan , di mana ia menjelaskan memberikan setiap elemen angka unik dan hashing angka-angka itu berada dalam kisaran yang lebih kecil.

Elemen-elemen dibuat menjadi angka unik dengan menafsirkannya sebagai basis-29 (0-9 dan AS). Saya kemudian menemukan bahwa %633%35%18mempersempit nilai ke kisaran [0, 17]sambil mempertahankan keunikan.

Cuplikan Tes

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
sumber
Oh, saya pikir cara Anda akan menyelamatkan saya beberapa byte juga!
Jonathan Allan
2

Clojure, 198 194 byte

Pembaruan: lebih baik fordaripada 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))))

Asli:

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

Saya ingin tahu apakah ada cara yang lebih ringkas untuk menyandikan tabel pencarian.

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

Cobalah online!

ovs
sumber
1

Mathematica, 390 338 329 Bytes

Disimpan 9 byte karena benar-benar terjaga sekarang dan benar-benar menggunakan pemendekan yang saya maksudkan.

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

Penjelasan: Temukan posisi semua karakter huruf besar. Letakkan satu titik di depan masing-masing. Pisahkan string di setiap titik. Untuk daftar substring ini, lakukan pembagian berikut berdasarkan huruf dan bagi berdasarkan angka. Untuk yang dibagi dengan huruf, konversi string ke angka. Untuk yang dibagi dengan digit, ganti setiap bahan kimia dengan berat molekulnya. Untuk siapa pun dengan berat molekul dan jumlah atom, gantilah dengan produk mereka. Mereka menemukan totalnya.

Versi 1:

Saya yakin ini bisa banyak golf (atau hanya ditulis ulang sepenuhnya). Saya hanya ingin mencari tahu bagaimana melakukannya. (Akan merenungkannya di pagi hari.)

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

Penjelasan: Pertama-tama pisahkan string menjadi karakter. Kemudian lipat array yang bergabung dengan huruf kecil dan angka kembali ke modal mereka. Selanjutnya tambahkan 1 ke bahan kimia apa pun tanpa nomor di ujungnya. Kemudian lakukan dua pemisahan istilah dalam array - satu pemisahan di semua angka dan satu pemisahan di semua huruf. Untuk yang pertama ganti huruf dengan massa molar mereka kemudian cari produk titik dari dua daftar ini.

Ian Miller
sumber
1

Python 3 - 408 byte

Ini terutama solusi @ovs, karena ia menurunkannya lebih dari 120 byte ... Lihat solusi awal di bawah ini.

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)

Cobalah online!

Python 3 - 550 548 535 byte (kehilangan hitungan dengan lekukan)

Disimpan 10 byte berkat @cairdcoinheringaahing dan 3 disimpan berkat ovs

Saya memiliki tujuan pribadi untuk tidak menggunakan regex apa pun, dan melakukannya dengan cara lama yang menyenangkan ... Ternyata lebih lama 350 byte daripada solusi regex, tetapi hanya menggunakan perpustakaan standar 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)  

Cobalah online!


Jika ada yang mau menurunkannya (dengan perbaikan lekukan dan trik lainnya ...), itu akan 100% diterima dengan baik, merasa seperti ada cara yang lebih baik untuk melakukan ini ...

Tuan Xcoder
sumber
Anda dapat mengganti for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]denganfor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
caird coinheringaahing
@cairdcoinheringaahing ah, bagus ... memperbarui ketika saya memiliki akses ke komputer
Tn. Xcoder
@ Terima kasih banyak! Mengreditkan Anda dalam jawaban
Tn. Xcoder
Dengan Python, Anda bisa menggunakan titik koma sebagai pengganti baris baru, yang memungkinkan Anda untuk menyimpan byte pada indentasi.
Pavel
@Phoenix tidak jika ada if/for/whiledi baris berikutnya. Karena ini adalah kasus pada setiap baris indentasi, Anda tidak dapat menyimpan byte dengan ini.
Ov