在Python中,如何创建链接列表的所有可能组合?

2024-10-03 04:30:26 发布

您现在位置:Python中文网/ 问答频道 /正文

在我所有的“家庭考试”之前,我总是有一个疯狂的、可能违反直觉的想法,那就是我可以创建一个列表,列出所有可能的公式组合。通过这样做,我可能能够将一些基本值输入到我从测试中得到的不同变量中,并得到适合问题的公式列表。基本示例:

欧姆定律

U = R * I

焦耳定律

P = U * I

但这两个列表可以合并:

P = R * I * I

I = U / R

这意味着

P = U * U / R

如何创建这些列表的所有可能组合?起初,我考虑创建不同的列表,例如

ohms_law = ['R', 'U', 'I']
jouls_law = ['P', 'U', 'I']
.
.
.

然而,这是实际连接它们的问题,以及实际等号、除号等放置在何处的问题

有谁能帮我更接近完成这个效率极低、毫无用处的想法吗?只是为了好玩

编辑:适用于教育程度较低、从未使用过配方奶粉的人

Formula 1: U = R * I
Formula 2: P = U * I

Output:
U = R * I
P = U * I
P = U * U / R
P = I * I * R
R = U / I
I = U / R
U = P / I
.
.
.
cont.

我在这里所做的只是将公式相互匹配。第一个公式表示U等于I乘以R。这意味着我们可以将它插入第二个公式,得到一个新的公式。我想要所有这些组合


Tags: 编辑示例列表家庭配方公式效率formula
1条回答
网友
1楼 · 发布于 2024-10-03 04:30:26

这里有一个建议。最终的结果是错误的,我不想花太多时间修复bug,但是你可以看到我是如何解决这个问题的

import typing
from dataclasses import dataclass


@dataclass
class Unit:  # as in Physical Quantity
    name: str


R = Unit("R")
U = Unit("U")
I = Unit("I")
P = Unit("P")
units = [R, U, I, P]


@dataclass
class Factor:
    unit: Unit
    dimension: int  # should not be zero

    def pretty(self) -> str:
        operand_sign = "*" if self.dimension > 0 else "/"
        return f"{operand_sign} {operand_sign.join(' ' + self.unit.name + ' ' for _ in range(abs(self.dimension)))}"


@dataclass
class Formula:  # only considering its quantities
    result: Unit
    factors: typing.List[Factor]

    def pretty(self) -> str:
        # TODO: this formatting is ugly, it produces "R = /  I  *  U " for example
        return f"{self.result.name} = " + " ".join(factor.pretty() for factor in self.factors)


ohms_law = Formula(U, [Factor(R, 1), Factor(I, 1)])
jouls_law = Formula(P, [Factor(U, 1), Factor(I, 1)])


# now we have to rewrite each formula in each combination of its factors/result
def reformulate(formula: Formula, unit: Unit) -> Formula:
    # FIXME: I am sure this function is incorrect, notably if unit is not of dimension -1 in the base formula
    assert unit in (_factor.unit for _factor in formula.factors)
    new_formula = Formula(
            result=unit,
            factors=[
                Factor(_factor.unit, dimension=-_factor.dimension)
                for _factor in formula.factors if _factor.unit != unit
            ] + [
                Factor(formula.result, dimension=1)
            ]
        )
    return new_formula


base_formulas = [ohms_law, jouls_law]
print("base formulas:")
for base_formula in base_formulas:
    print(base_formula.pretty())

formulas = base_formulas + [
    reformulate(base_formula, factor.unit)
    for base_formula in base_formulas
    for factor in base_formula.factors
]
print("base reformulations:")
for formula in formulas:
    print(formula.pretty())


# it will be handy to know, for each quantity, which formula can produce it
formulas_by_unit: typing.Dict[str, typing.List[Formula]] = {
    unit.name: # NOTE: we have to hash by `unit.name` because a Unit is not simply hashable, but a string is
        [formula for formula in formulas
         if (unit == formula.result)]
    for unit in units
}
print("possible formulas for substitution:")
print("\n".join(unit_name + ": " + str([formula.pretty() for formula in formulas])
                for unit_name, formulas in formulas_by_unit.items()))


# now that we have set the data and its structure, we can create new formulas

def substitute(formula1: Formula, common_unit: Unit, formula2: Formula) -> Formula:
    """Replace the common_unit from formula1 with its definition from formula2."""
    return Formula(
        result=formula1.result,
        factors=merge_factors(
            # FIXME: take into account that the factor from formula1 may have a dimension != 1
            [factor for factor in formula1.factors if factor.unit != common_unit],
            formula2.factors
        )

    )


def merge_factors(factors1: typing.List[Factor], factors2: typing.List[Factor]) -> typing.List[Factor]:
    """Merge the two lists of factors, combining those of the same unit by adding their dimension."""
    factors1_by_unit = {factor.unit.name: factor for factor in factors1}
    factors2_by_unit = {factor.unit.name: factor for factor in factors2}
    units_only_in_factors1 = set(factors1_by_unit.keys()).difference(factors2_by_unit)
    units_only_in_factors2 = set(factors2_by_unit.keys()).difference(factors1_by_unit)
    units_in_both = set(factors1_by_unit.keys()).intersection(factors2_by_unit)
    return [
        *(factors1_by_unit[unit_name] for unit_name in units_only_in_factors1),
        *(factors2_by_unit[unit_name] for unit_name in units_only_in_factors2),
        *(
            Factor(unit=Unit(unit_name), dimension=factor1.dimension + factor2.dimension)
            for unit_name in units_in_both
            for factor1 in (factors1_by_unit[unit_name],)
            for factor2 in (factors2_by_unit[unit_name],)
            if factor1.dimension + factor2.dimension != 0
        )
    ]


print("reformulations:")
for base_unit in units:
    for base_formula in formulas_by_unit[base_unit.name]:
        # find possible substitutions
        for substituable_factor in base_formula.factors:
            for candidate_substitution_formula in formulas_by_unit[substituable_factor.unit.name]:
                if base_unit not in (factor.unit for factor in candidate_substitution_formula.factors):
                    reformulation = substitute(base_formula, substituable_factor.unit, candidate_substitution_formula)
                    print(reformulation.pretty())
base formulas:
U = *  R  *  I 
P = *  U  *  I 
base reformulations:
U = *  R  *  I 
P = *  U  *  I 
R = /  I  *  U 
I = /  R  *  U 
U = /  I  *  P 
I = /  U  *  P 
possible formulas for substitution:
R: ['R = /  I  *  U ']
U: ['U = *  R  *  I ', 'U = /  I  *  P ']
I: ['I = /  R  *  U ', 'I = /  U  *  P ']
P: ['P = *  U  *  I ']
reformulations:
R = *  P 
R = *  P  /  I / I 
P = *  R  *  I * I 
P = /  R  *  U * U 

例如,第一个结果是R = * P ,这是错误的
它试图用'I = / U * P '重新格式化'R = / I * U '。但是I有维度-1,这没有被考虑进去。所以它看到两个U,一个是维度1,一个是维度-1,并将它们抵消

除了这些错误,你应该能够理解我是如何进行的

相关问题 更多 >