首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Python计算分子化合物中元素的数量(如果可能的话递归)?

用Python计算分子化合物中元素的数量(如果可能的话递归)?
EN

Stack Overflow用户
提问于 2022-01-31 11:01:42
回答 2查看 464关注 0票数 3

所以我试着编写一些代码来告诉我任何给定化合物中元素的数量。我甚至不知道从哪里开始:我试着编写一些东西,但后来意识到它只适用于简单的化合物(或者根本不起作用)。下面是我想要的一个例子:

代码语言:javascript
复制
>>> function_input : 'NaMg3Al6(BO3)3Si6O18(OH)4', 'O'

>>> function_return : 31

到目前为止,我的代码非常混乱(IT不工作,它只是说明了我粗略的思考过程):

代码语言:javascript
复制
def get_pos_from_count(string: str, letter: str):
    count = string.count(letter)
    lens = [-1]
    for i in range(count):
        lens += [string[lens[i] + 1:].index(letter) + lens[i] + 1]
    return lens[1:]



def find_number(string, letter):
    if string.count(letter) == 0: return 0
    numbers = '1234567890'
    try:
        mul1 = int(string[0])
    except ValueError:
        mul1 = 0
    mul2 = []
    sub_ = 1
    list_of_positions = get_pos_from_count(string, letter)
    for i in list_of_positions:
        try:
            sub_ += int(string[i + 1]) if string[i + 1] in numbers else 0
        except IndexError: pass
        if string[i + 1:].count(')') > string[i + 1].count('('):
            try:
                mul2 += int(string[string[i + 1:].count(')') + 1])
            except (IndexError, ValueError): pass
    return mul1 * sub_ * mul2

我试图实施的办法是:

string)

  • Return

  • 查找该元素在复合词中出现的次数。

  • 查找每个下标,如果所述元素位于括号内,则在括号外乘以下标。

  • 求和所有下标,乘以化合物数(在
  1. 中的第一个字符为用户

)。

但后来我意识到我的代码要么非常长,要么需要递归,我不知道如何在这里应用。

如果可能的话,我想要一个半工作的函数,但是关于如何处理这个问题的快速提示也是有帮助的!

如果可能的话,我不想使用外部库。

tl;dr:元素原子性的This question,没有外部库(如果可能的话)。

编辑:是的,我链接的问题确实有关于如何做到这一点的提示,但是当我试图使任何代码只对一个元素工作,并将其权重设置为1时,我遇到了许多我不知道要解决的问题。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-31 19:59:07

让我们把这项任务分成三个部分:

将字符串标记为元素、数字的列表,并将方括号标记为具有嵌套列表的嵌套列表。brackets;

  • Parse .

介绍我的工具:

标记:more_itertools.split_when;

  • Parsing方括号: recursion;

代码语言:javascript
复制
from more_itertools import split_when, pairwise
from itertools import chain
from collections import Counter

def nest_brackets(tokens, i = 0):
    l = []
    while i < len(tokens):
        if tokens[i] == ')':
            return i,l
        elif tokens[i] == '(':
            i,subl = nest_brackets(tokens, i+1)
            l.append(subl)
        else:
            l.append(tokens[i])
        i += 1
    return i,l

def parse_compound(s):
    tokens = [''.join(t) for t in split_when(s, lambda a,b: b.isupper() or b in '()' or (b.isdigit() and not a.isdigit()))]
    tokens = [(int(t) if t.isdigit() else t) for t in tokens]
    i, l = nest_brackets(tokens)
    assert(i == len(tokens)) # crash if unmatched ')'
    return l

def count_elems(parsed_compound):
    c = Counter()
    for a,b in pairwise(chain(parsed_compound, (1,))):
        if not isinstance(a, int):
            subcounter = count_elems(a) if isinstance(a, list) else {a: 1}
            n = b if isinstance(b, int) else 1
            for elem,k in subcounter.items():
                c[elem] += k * n
    return c

s = 'NaMg3Al6(B(CO2)3)3Si6O18(OH)4'

l = parse_compound(s)
print(l)
# ['Na', 'Mg', 3, 'Al', 6, ['B', ['C', 'O', 2], 3], 3, 'Si', 6, 'O', 18, ['O', 'H'], 4]


c = count_elems(l)
print(c)
# Counter({'O': 40, 'C': 9, 'Al': 6, 'Si': 6, 'Mg': 3, 'B': 3, 'Na': 1})

print(c['O'])
# 40
票数 2
EN

Stack Overflow用户

发布于 2022-01-31 12:50:34

尝试使用这个递归函数:

代码语言:javascript
复制
import re

def find_number(s, e):
    if s == '':
        return 0
    x = re.search('\(([A-Za-z0-9]*)\)([0-9]*)', s)
    if x is not None:
        return (find_number(s[:x.start()] + s[x.end():], e) +
                find_number(x.groups()[0], e) * int(x.groups()[1] or '1'))
    return sum(int(x.groups()[0] or '1')
               for x in re.finditer(f'{e}([0-9]*)', s))

示例:

代码语言:javascript
复制
>>> find_number('NaMg3Al6(BO3)3Si6O18(OH)4', 'O')
31
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70924875

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档