Tìm Mr của một hợp chất nhất định!


12

Thử thách

Cho công thức của một hóa chất, tạo ra M r của hợp chất.

Phương trình

Mỗi nguyên tố trong hợp chất được theo sau bởi một số biểu thị số lượng nguyên tử đã nói trong hợp chất. Nếu không có số, chỉ có một nguyên tử đó trong hợp chất.

Một số ví dụ:

  • Ethanol (C 2 H 6 O) sẽ là C2H6Onơi có hai nguyên tử carbon, 6 nguyên tử hydro và 1 nguyên tử oxy
  • Magiê Hydroxide (MgO 2 H 2 ) sẽ là MgO2H2nơi có một nguyên tử magiê, hai nguyên tử oxy và hai nguyên tử hydro.

Lưu ý rằng bạn sẽ không bao giờ phải xử lý dấu ngoặc và mỗi phần tử chỉ được đưa vào một lần trong công thức.

Trong khi hầu hết mọi người có thể sẽ tuân theo đơn đặt hàng mà họ cảm thấy thoải mái nhất, không có hệ thống đặt hàng nghiêm ngặt. Ví dụ, nước có thể được cho là một trong hai H2Ohoặc OH2.

M r

Lưu ý: Ở đây, giả sử khối lượng công thức giống như khối lượng phân tử

M r của một hợp chất, khối lượng phân tử, là tổng trọng lượng nguyên tử của các nguyên tử trong phân tử.

Các yếu tố duy nhất và trọng lượng nguyên tử của chúng đến 1 vị trí thập phân mà bạn phải hỗ trợ (hydro thành canxi, không bao gồm các khí hiếm) như sau. Họ cũng có thể được tìm thấy ở đây

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

Bạn phải luôn luôn cung cấp đầu ra cho một vị trí thập phân.

Ví dụ, ethanol ( C2H6O) có M r của 46.0vì nó là tổng của khối lượng nguyên tử của các nguyên tố trong đó:

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

Đầu vào

Một chuỗi đơn ở định dạng trên. Bạn có thể đảm bảo rằng các phần tử có trong phương trình sẽ là các ký hiệu nguyên tố thực tế.

Các hợp chất nhất định không được đảm bảo tồn tại trong thực tế.

Đầu ra

Tổng M r của hợp chất, đến 1 chữ số thập phân.

Quy tắc

Nội dung mà phần tử truy cập hoặc dữ liệu hóa học không được phép (xin lỗi Mathicala)

Ví dụ

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

Chiến thắng

Mã ngắn nhất trong byte thắng.

Bài đăng này đã được thông qua với sự cho phép từ caird coinheringaahing . (Bài viết đã bị xóa)


Chúng ta có phải xử lý các bộ định lượng, chẳng hạn như : 2H2O?
Ông Xcoder

6
Đối với người tò mò, đây là giải pháp Mathicala (53 byte):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min

Câu trả lời:


6

Thạch , 63 byte

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

Một liên kết đơn âm chấp nhận một danh sách các ký tự và trả về một số.

Hãy thử trực tuyến!

Làm sao?

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

Đây là một trong những câu trả lời Jelly dài nhất tôi từng thấy, nhưng nó vẫn chưa bằng một nửa thời lượng của chương trình hiện tại ở vị trí thứ hai, rất tốt!
Gryphon

6

Python 3 ,  189 182  168 byte

-14 byte bằng cách sử dụng hàm băm từ câu trả lời JavaScript (ES6) của Justin Marin .

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

Hãy thử trực tuyến!


Dưới đây là phiên bản 182 byte, tôi sẽ để lại lời giải thích cho phiên bản này - ở trên chỉ thay đổi thứ tự các trọng số, sử dụng intđể chuyển đổi tên thành phần từ cơ sở 29và sử dụng các khoản cổ tức khác nhau để nén phạm vi số nguyên xuống - xem Justin Câu trả lời của Mariners .

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

Một hàm không tên chấp nhận một chuỗi svà trả về một số.

Hãy thử trực tuyến!

Làm sao?

Sử dụng biểu thức chính để phân tách đầu vào, sthành các phần tử và số đếm của chúng bằng cách sử dụng:
re.findall("(\D[a-z]?)(\d*)",s)
\Dkhớp chính xác một chữ số không và [a-z]?khớp 0 hoặc 1 chữ cái viết thường, cùng với các phần tử khớp. \d*khớp 0 hoặc nhiều chữ số. Các dấu ngoặc làm cho chúng thành hai nhóm và như vậy findall("...",s)sẽ trả về một danh sách các bộ chuỗi , [(element, number),...].

Số này rất đơn giản để trích xuất, điều duy nhất cần xử lý là một chuỗi rỗng có nghĩa là 1, điều này đạt được bằng logic orvì các chuỗi Python là falsey : int(n or 1).

Chuỗi phần tử được cung cấp một số duy nhất bằng cách lấy sản phẩm của các ký tự đầu tiên và ký tự cuối cùng của nó (thường là cùng một ví dụ như S hoặc C, nhưng chúng ta cần phân biệt giữa Cl, C, Ca và Na để chúng ta không thể sử dụng một tính cách).

Những con số này sau đó được băm để bao phủ phạm vi nhỏ hơn nhiều [0,18], được tìm thấy bởi một tìm kiếm của không gian modulo dẫn đến %1135%98%19. Ví dụ "Cl"có ordinals 67108, trong đó nhân để cung cấp cho 7736, trong đó, modulo 1135426, mà modulo 9834, mà modulo 1915; con số này được sử dụng để lập chỉ mục vào danh sách các số nguyên - giá trị thứ 15 (0 chỉ mục) trong danh sách:
[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, trọng lượng nguyên tử của Cl, sau đó được nhân với số lượng các phần tử như vậy (như đã tìm thấy ở trên).

Những sản phẩm này sau đó được thêm vào với nhau bằng cách sử dụng sum(...).


Bạn là một thiên tài ... vượt xa tôi hơn 350 byte
Ông 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);

Hãy thử trực tuyến!

Thay vì 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])bạn có thể sử dụng [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]với cùng số lượng 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

Lấy cảm hứng từ câu trả lời Python của Jonathan Allan , nơi ông giải thích cho mỗi phần tử một số duy nhất và băm các số đó trong một phạm vi nhỏ hơn.

Các phần tử được tạo thành các số duy nhất bằng cách giải thích chúng là cơ sở 29 (0-9 và AS). Sau đó tôi thấy rằng %633%35%18thu hẹp các giá trị xuống phạm vi [0, 17]trong khi duy trì tính duy nhất.

Kiểm tra đoạn trích

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>


Ồ, tôi nghĩ rằng cách của bạn cũng sẽ tiết kiệm cho tôi một vài byte!
Jonathan Allan

2

Clojure, 198 194 byte

Cập nhật: tốt forhơn so với 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))))

Nguyên:

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

Tôi đang tự hỏi nếu có một cách nhỏ gọn hơn để mã hóa bảng tra cứu.


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

Hãy thử trực tuyến!


1

Toán học, 390 338 329 byte

Đã lưu 9 byte do thực sự thức dậy bây giờ và thực sự sử dụng rút ngắn tôi dự định.

Phiên bản 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]&

Giải thích: Tìm vị trí của tất cả các ký tự viết hoa. Đặt một dấu chấm trước mỗi. Tách chuỗi ở mỗi dấu chấm. Đối với danh sách các chuỗi con này, hãy thực hiện phân tách sau dựa trên các chữ cái và phân tách dựa trên các chữ số. Đối với những người được phân chia bằng các chữ cái chuyển đổi chuỗi thành số. Đối với những cái được phân chia bằng chữ số thay thế mỗi hóa chất với trọng lượng phân tử của nó. Đối với bất kỳ trọng lượng phân tử và số lượng nguyên tử thay thế nó bằng sản phẩm của chúng. Họ tìm thấy tổng số.

Phiên bản 1:

Tôi chắc chắn rằng điều này có thể được đánh golf rất nhiều (hoặc chỉ viết lại hoàn toàn). Tôi chỉ muốn tìm ra cách để làm điều đó. (Sẽ phản ánh về nó vào buổi sáng.)

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

Giải thích: Đầu tiên chia chuỗi thành các ký tự. Sau đó gập qua mảng nối các ký tự chữ thường và số trở về thủ đô của chúng. Tiếp theo nối 1 vào bất kỳ hóa chất nào mà không có số ở cuối. Sau đó thực hiện hai phần tách của các điều khoản trong mảng - một phần tách ở tất cả các số và một phần tách ở tất cả các chữ cái. Đối với người đầu tiên thay thế các chữ cái với khối lượng mol của họ sau đó tìm sản phẩm chấm của hai danh sách này.


1

Python 3 - 408 byte

Đây chủ yếu là giải pháp của @ovs, vì anh ta đã đánh nó xuống hơn 120 byte ... Xem giải pháp ban đầu bên dưới.

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)

Hãy thử trực tuyến!

Python 3 - 550 548 535 byte (mất số đếm khi thụt lề)

Đã lưu 10 byte nhờ @cairdcoinheringaahing và 3 lưu nhờ vào lò nướng

Tôi đã có một mục tiêu cá nhân là không sử dụng bất kỳ regex nào và thực hiện theo cách cũ, vui nhộn ... Hóa ra nó dài hơn 350 byte so với giải pháp regex, nhưng nó chỉ sử dụng thư viện chuẩn của 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)  

Hãy thử trực tuyến!


Nếu bất cứ ai sẵn sàng đánh nó xuống (với các bản sửa lỗi thụt đầu dòng và các thủ thuật khác ...), nó sẽ được đón nhận 100%, cảm giác như có một cách tốt hơn để làm điều này ...


Bạn có thể thay thế for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]bằngfor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
caird coinheringaahing

@cairdcoinheringaahing ah, thật tuyệt ... cập nhật khi tôi có quyền truy cập vào máy tính
Ông Xcoder

@ovs Cảm ơn rất nhiều! Tín dụng bạn trong câu trả lời
Ông Xcoder

Trong Python, bạn có thể sử dụng dấu chấm phẩy thay cho dòng mới, cho phép bạn lưu byte khi thụt lề.
Pavel

@Phoenix không nếu có một if/for/whiledòng tiếp theo. Vì đây là trường hợp trên mỗi dòng thụt lề, bạn không thể lưu byte bằng cách này.
trứng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.