ค้นหานายแห่งสารประกอบให้!


12

ท้าทาย

เมื่อกำหนดสูตรของสารเคมีให้ส่งออก M rของสารประกอบ

สมการ

แต่ละองค์ประกอบในสารประกอบจะตามด้วยตัวเลขที่แสดงถึงจำนวนอะตอมดังกล่าวในสารประกอบ หากไม่มีตัวเลขแสดงว่ามีอะตอมเพียงหนึ่งเดียวในสารประกอบ

ตัวอย่างบางส่วนคือ:

  • เอทานอล (C 2 H 6 O) จะเป็นC2H6Oที่ซึ่งมีอะตอมของคาร์บอนสองอะตอมอะตอมไฮโดรเจน 6 อะตอมและออกซิเจน 1 อะตอม
  • แมกนีเซียมไฮดรอกไซด์ (MgO 2 H 2 ) จะอยู่MgO2H2ตรงที่มีอะตอมแมกนีเซียมหนึ่งอะตอมออกซิเจนสองอะตอมและไฮโดรเจนสองอะตอม

โปรดทราบว่าคุณจะไม่ต้องจัดการกับวงเล็บและแต่ละองค์ประกอบจะรวมอยู่เพียงครั้งเดียวในสูตร

ในขณะที่คนส่วนใหญ่อาจจะยึดตามคำสั่งที่พวกเขารู้สึกสะดวกสบายที่สุด แต่ก็ไม่มีระบบการสั่งซื้อที่เข้มงวด ยกตัวอย่างเช่นน้ำอาจจะได้รับเป็นอย่างใดอย่างหนึ่งหรือH2OOH2

เอ็มอาร์

หมายเหตุ: ที่นี่สมมติว่าสูตรมวลนั้นเหมือนกับมวลโมเลกุล

M rของสารประกอบคือมวลโมเลกุลคือผลรวมของน้ำหนักอะตอมของอะตอมในโมเลกุล

องค์ประกอบเท่านั้นและน้ำหนักอะตอมของพวกเขาถึงทศนิยม 1 ตำแหน่งที่คุณต้องสนับสนุน (ไฮโดรเจนกับแคลเซียมไม่รวมถึงก๊าซมีตระกูล) มีดังนี้ พวกเขาสามารถพบได้ที่นี่

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

คุณควรให้ผลลัพธ์กับทศนิยมหนึ่งตำแหน่งเสมอ

ยกตัวอย่างเช่นเอทานอล ( C2H6O) มี M Rของ46.0มันเป็นผลรวมของน้ำหนักอะตอมของธาตุในนั้นที่:

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

อินพุต

สตริงเดี่ยวในรูปแบบข้างต้น คุณสามารถรับประกันได้ว่าองค์ประกอบที่รวมอยู่ในสมการจะเป็นสัญลักษณ์องค์ประกอบจริง

สารประกอบที่ให้นั้นไม่รับประกันว่าจะมีอยู่จริง

เอาท์พุต

เอ็มรวมRของสารประกอบที่ไปยังสถานที่ 1 ทศนิยม

กฎระเบียบ

บิลด์อินซึ่งองค์ประกอบการเข้าถึงหรือข้อมูลทางเคมีไม่ได้รับอนุญาต (ขออภัย Mathematica)

ตัวอย่าง

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

การชนะ

รหัสที่สั้นที่สุดในหน่วยไบต์ชนะ

โพสต์นี้ถูกนำมาใช้โดยได้รับอนุญาตจากcoinheringaahing Caird (ลบโพสต์ทันที)


เรามีการจัดการปริมาณเช่น: 2H2O?
นาย Xcoder

6
สำหรับคนที่อยากรู้อยากเห็นนี่คือทางออกของ Mathematica (53 bytes):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min

คำตอบ:


6

เยลลี่ 63 ไบต์

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

ลิงก์ monadic ยอมรับรายการของอักขระและส่งคืนตัวเลข

ลองออนไลน์!

อย่างไร?

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

นี่เป็นหนึ่งในคำตอบที่เจลลี่ที่ยาวที่สุดที่ฉันเคยเห็นมา แต่มันก็ยังน้อยกว่าครึ่งหนึ่งของความยาวของโปรแกรมในปัจจุบันในวินาทีที่ทำได้ดีมาก!
Gryphon

6

Python 3 ,  189 182  168 ไบต์

-14 ไบต์โดยใช้กัญชาจากจัสตินนาวินของ 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)])

ลองออนไลน์!


ด้านล่างเป็นรุ่น 182 ไบต์ฉันจะทิ้งคำอธิบายไว้ - อันนี้แค่เปลี่ยนลำดับของน้ำหนักใช้intในการแปลงชื่อองค์ประกอบจากฐาน29และใช้เงินปันผลที่แตกต่างกันในการบีบอัดช่วงจำนวนเต็มลง - ดูJustin คำตอบของ

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

ฟังก์ชั่นที่ไม่มีชื่อรับสายsและกลับจำนวน

ลองออนไลน์!

อย่างไร?

ใช้ regex เพื่อแยกอินพุต, sเป็นองค์ประกอบและการนับโดยใช้:
re.findall("(\D[a-z]?)(\d*)",s)
\Dจับคู่หนึ่งที่ไม่ใช่ตัวเลขและ[a-z]?ตรงกับตัวอักษรตัวพิมพ์เล็ก 0 หรือ 1 ตัวรวมองค์ประกอบที่ตรงกัน \d*ตรงกับตัวเลข 0 หรือมากกว่า วงเล็บทำให้เหล่านี้ออกเป็นสองกลุ่มและเป็นเช่นfindall("...",s)ผลตอบแทนรายการ tuples [(element, number),...]สตริง,

จำนวนที่ง่ายต่อการสกัดสิ่งเดียวที่จับคือสตริงที่ว่างเปล่าหมายถึง 1 นี้จะประสบความสำเร็จกับตรรกะorตั้งแต่สตริงหลามมี int(n or 1)falsey:

สตริงองค์ประกอบจะได้รับหมายเลขที่ไม่ซ้ำกันโดยการใช้ผลิตภัณฑ์ของตัวอักษรตัวแรกและตัวสุดท้าย (โดยปกติจะเป็นตัวเดียวกันเช่น S หรือ C แต่เราต้องแยกความแตกต่างระหว่าง Cl, C, Ca และ Na ดังนั้นเราจึงไม่สามารถใช้ ตัวอักษร)

ตัวเลขเหล่านี้จะถูกแฮชเพื่อให้ครอบคลุมช่วงที่เล็กกว่ามาก [0,18] ซึ่งพบได้จากการค้นหาพื้นที่โมดูโลที่เกิด%1135%98%19ขึ้น ตัวอย่างเช่น"Cl"มี ordinals 67และ108ซึ่งคูณที่จะให้7736ซึ่งโมดูโล1135คือ426ซึ่งโมดูโล98คือ34ซึ่งโมดูโล19คือ15; หมายเลขนี้ใช้เพื่อจัดทำดัชนีในรายการจำนวนเต็ม - ค่า 15 (0 ดัชนี) ในรายการ:
[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น้ำหนักอะตอมมิกของ Cl ซึ่งจะถูกคูณด้วยจำนวนขององค์ประกอบดังกล่าว (ตามที่พบด้านบน)

sum(...)ผลิตภัณฑ์เหล่านี้มีการเพิ่มแล้วด้วยกันโดยใช้


คุณเป็นอัจฉริยะ ... แซงหน้าฉันไปกว่า 350 ไบต์
Mr. Xcoder

4

PHP , 235 ไบต์

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

ลองออนไลน์!

แทนที่จะ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])ใช้[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 ไบต์

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

ได้รับแรงบันดาลใจจากคำตอบ Python ของ Jonathan Allanซึ่งเขาอธิบายให้แต่ละองค์ประกอบมีจำนวนที่ไม่ซ้ำกันและทำให้ตัวเลขเหล่านั้นอยู่ในช่วงที่สั้นลง

องค์ประกอบถูกทำให้เป็นตัวเลขที่ไม่ซ้ำกันโดยการตีความพวกเขาเป็นฐาน -29 (0-9 และ AS) จากนั้นฉันก็พบว่า%633%35%18ทำให้ค่าแคบลงจนถึงช่วง[0, 17]ที่ยังคงเอกลักษณ์

ตัวอย่างการทดสอบ

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>


โอ้ฉันคิดว่าวิธีของคุณจะช่วยฉันสักสองสามไบต์เช่นกัน!
Jonathan Allan

2

Clojure, 198 194 ไบต์

ปรับปรุง: ดีกว่าที่จะกว่าforreduce

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

เดิม:

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

ฉันสงสัยว่ามีวิธีกะทัดรัดในการเข้ารหัสตารางค้นหาหรือไม่



1

Mathematica, 390 338 329 ไบต์

บันทึกแล้ว 9 ไบต์เนื่องจากตอนนี้รู้สึกตัวแล้วและกำลังใช้ shortening ที่ฉันตั้งใจไว้

รุ่น 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]&

คำอธิบาย: ค้นหาตำแหน่งของอักขระตัวพิมพ์ใหญ่ทั้งหมด ใส่จุดก่อนหน้า แยกสตริงที่แต่ละจุด สำหรับรายการของสตริงย่อยนี้ให้แบ่งตามตัวอักษรและแยกตามตัวเลข สำหรับคนที่แยกด้วยตัวอักษรแปลงสตริงเป็นตัวเลข สำหรับคนที่แยกเป็นตัวเลขจะแทนที่สารเคมีแต่ละชนิดด้วยน้ำหนักโมเลกุล สำหรับสิ่งใดก็ตามที่มีน้ำหนักโมเลกุลและจำนวนอะตอมจะแทนที่ด้วยผลิตภัณฑ์ของพวกเขา พวกเขาพบว่าทั้งหมด

รุ่น 1:

ฉันแน่ใจว่านี่สามารถเล่นกอล์ฟได้มาก (หรือเพิ่งเขียนใหม่ทั้งหมด) ฉันแค่อยากจะรู้ว่าจะทำยังไง (จะสะท้อนกลับในตอนเช้า)

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

คำอธิบาย: ก่อนอื่นแบ่งสตริงเป็นอักขระ จากนั้นจึงพับอาร์เรย์ที่รวมตัวอักษรตัวเล็กและตัวเลขกลับไปที่ทุน ถัดไปผนวก 1 กับสารเคมีใด ๆ โดยไม่ต้องตัวเลขในตอนท้าย จากนั้นให้แยกคำสองคำในอาร์เรย์โดยแยกหนึ่งครั้งที่ตัวเลขทั้งหมดและแยกหนึ่งตัวอักษรทั้งหมด สำหรับการแทนที่ตัวอักษรตัวแรกด้วยมวลโมลาร์ของพวกมันแล้วหาผลคูณของจุดของสองรายการนี้


1

Python 3 - 408 ไบต์

นี่เป็นวิธีแก้ปัญหาส่วนใหญ่ของ @ovs เพราะเขาตีกอล์ฟลงได้มากกว่า 120 ไบต์ ... ดูวิธีแก้ปัญหาเบื้องต้นด้านล่าง

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)

ลองออนไลน์!

Python 3 - 550 548 535 bytes (เสียการนับด้วยการเยื้อง)

บันทึก 10 ไบต์ด้วย@cairdcoinheringaahingและอีก 3 บันทึกด้วยขอบคุณ ovs

ฉันมีเป้าหมายส่วนตัวที่จะไม่ใช้ regex ใด ๆ และทำมันด้วยความสนุกแบบโรงเรียนเก่า ... มันกลับกลายเป็น 350 ไบต์นานกว่าโซลูชัน regex แต่ใช้ไลบรารีมาตรฐานของ 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)  

ลองออนไลน์!


หากทุกคนยินดีที่จะตีมัน (พร้อมการแก้ไขการเยื้องและเทคนิคอื่น ๆ ... ) มันจะได้รับการตอบรับที่ดี 100% ให้ความรู้สึกว่ามีวิธีที่ดีกว่าในการทำเช่นนี้ ...


คุณสามารถแทนที่for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]ด้วยfor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
caird coinheringaahing

@cairdcoinheringaahing อ่าดี ... อัปเดตเมื่อฉันมีคอมพิวเตอร์
Mr. Xcoder

@ovs ขอบคุณมาก! ให้เครดิตคุณในคำตอบ
นาย Xcoder

ใน Python คุณสามารถใช้เครื่องหมายอัฒภาคแทนการขึ้นบรรทัดใหม่ซึ่งช่วยให้คุณสามารถบันทึกไบต์ในการเยื้อง
Pavel

@ ฟีนิกซ์ไม่ได้หากมีif/for/whileในบรรทัดถัดไป เนื่องจากเป็นกรณีนี้ในทุกบรรทัดที่มีการเยื้องคุณไม่สามารถบันทึกไบต์ได้
OVS
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.