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

标签 python python-3.x recursion chemistry

所以我正在尝试编写一些代码来告诉我任何给定化合物中元素的数量。我什至不确定从哪里开始:我尝试编写一些代码,但后来意识到它只适用于简单的化合物(或者根本不起作用)。这是我想要的示例:

>>> function_input : 'NaMg3Al6(BO3)3Si6O18(OH)4', 'O'

>>> function_return : 31

到目前为止,我的代码一团糟(它不起作用,它只是说明了我粗略的思考过程):

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

我尝试实现的方法是:

  1. 找出该元素在化合物中出现的次数。
  2. 找到每个下标,如果所述元素在括号内则乘以括号外的下标。
  3. 总结所有下标,乘以化合物的数量(字符串中的第一个字符)
  4. 将所述号码返回给用户

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

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

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

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

编辑:是的,我链接的问题确实有关于如何执行此操作的提示,但是当我尝试使任何代码仅适用于一个元素并将其权重设置为 1 时,我运行了陷入许多我不知道要解决的问题。

最佳答案

让我们将任务分为三个部分:

  • 将字符串标记为元素、数字和括号的列表;
  • 解析括号以获得带有子列表的嵌套列表;
  • 计算嵌套列表中的元素。

介绍我的工具:

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

关于python - 用 Python 计算分子化合物中的元素数量(如果可能的话递归)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70924875/

相关文章:

javascript - 遍历递归json树并合并

java - 递归java方法解析带条件的字符串?

python - Twisted 和命令行界面

python - 为什么人们在 __get__ 中将 owner 参数默认为 None?

python-3.x - 链接到python 3中字节对象的一部分

python - 用于匹配除标点符号之外的所有非单词的正则表达式?

java - 我的探路者在寻找最短路径时遇到问题

python - OSError : [WinError 123] The filename, 目录名称或卷标语法不正确: '<frozen importlib._bootstrap>' 对于 django 项目

python - git-python 从存储库获取提交提要

python - Alpine Docker 定义特定的 python 版本 (python3-3.8.7-r0 :breaks: world[python3=3. 6.9-r3])