首页 > 解决方案 > 寻找pythonic的优雅:字典而不是重复的意大利面条块

问题描述

我有一个将嵌套列表转换为 LaTeX 格式表的脚本。棘手的部分与按其值着色的单元格有关。假设我有一个这样的嵌套列表:

[[0.40, -0.13, 0.00, 0.00, 0.00], [-1.90, -0.56, -0.57, -0.66, -1.37], [4.07, 0.24, 2.56, 0.02, 0.02], [6.43, 0.23, 0.33, 0.18, 0.02], [11.80, 4.81, 4.86, 3.96, 6.03], [4.05, 1.94, 0.09, 0.01, 0.03]]

我脚本的那部分是这样的

for fila in listainicial:
#seudocódigo
    mes1 = ""
    mes2 = ""
    mes3 = ""
    mes4 = ""
    mes5 = ""
if float(fila[0]) >= 100:
        mes1 = "\\footnotesize{}\\cellcolor{100pc}"
    elif float(fila[0]) > 30:
        mes1 = "\\footnotesize{}\\cellcolor{masde30pc}"
    elif float(fila[0]) > 20:
        mes1 = "\\footnotesize{}\\cellcolor{20to30pc}"
    elif float(fila[0]) > 10:
        mes1 = "\\footnotesize{}\\cellcolor{10to20pc}"
    elif float(fila[0]) > 5:
        mes1 = "\\footnotesize{}\\cellcolor{5to10pc}"
    elif float(fila[0]) > 0:
        mes1 = "\\footnotesize{}\\cellcolor{0to5pc}"
    elif float(fila[0]) == 0:
        mes1 = "\\footnotesize{}\\cellcolor{0pc}"
    elif float(fila[0]) > -5:
        mes1 = "\\footnotesize{}\\cellcolor{m5to0pc}"
    elif float(fila[0]) > -10:
        mes1 = "\\footnotesize{}\\cellcolor{m10tom5pc}"
    elif float(fila[0]) > -25:
        mes1 = "\\footnotesize{}\\cellcolor{m25tom10pc}"
    elif float(fila[0]) <= -25:
        mes1 = "\\footnotesize{}\\cellcolor{menosdem25pc}\\color{white}"

代码从fila[1] 到fila[4] 重复

这太不合情理了,我觉得有点脏。我的脚本有效,复制粘贴块不是问题,但正如我在标题中指出的那样,我想生成更优雅和令人满意的代码。

我真的很想用字典代替如此冗长而单调的 if...elif 系列。我也将不胜感激任何其他解决方案,它可以减少我的 110 行长的脚本部分。

在这个意义上,我真的很感激任何提示或解决方案

提前致谢

标签: pythondictionarynested-lists

解决方案


这是我尝试封装您的代码并使其不那么笨拙的尝试:

上面的所有if name == main内容都可以提取到一个单独的模块中,使您的主要代码如下所示:

boundaries = [float('-inf'), -25, -10, -5, 0 - EPSILON, 0 + EPSILON, 5, 10, 20, 30, 100, float('inf')]
listainicial = [the values you have]
latex_string_values =  get_latex_values(listainicial, boundaries)

我添加了文档字符串来解释每个类/方法的作用;如果需要更多解释,请告诉我。

from typing import NamedTuple, List


EPSILON = 1e-8


class Interval(NamedTuple):
    """represents an interval on the number line, where the high value is included
    """
    low : float
    high : float

    def contains(self, value: float)-> bool:
        return self.low < value <= self.high


class Intervals:
    """represents a collection of Interval on the number line
    """
    def __init__(self, boundaries: List[float]):
        self.intervals = [Interval(low=low, high=high)
                          for low, high in zip(boundaries[:-1], boundaries[1:])]

    def get_interval(self, value: float)-> Interval:
        """returns the interval the value belongs to
        """
        for interval in self.intervals:
            if interval.contains(value):
                return interval
        raise ValueError('this value does not belong here')

    def __iter__(self):
        for interval in self.intervals:
            yield interval


class LatexValues:
    """a class that parses and assigns latex strings based on whether a value
    is contained in an interval
    """
    latex_values = ["\\footnotesize{}\\cellcolor{menosdem25pc}\\color{white}",
                    "\\footnotesize{}\\cellcolor{m25tom10pc}",
                    "\\footnotesize{}\\cellcolor{m10tom5pc}",
                    "\\footnotesize{}\\cellcolor{m5to0pc}",
                    "\\footnotesize{}\\cellcolor{0pc}",
                    "\\footnotesize{}\\cellcolor{0to5pc}",
                    "\\footnotesize{}\\cellcolor{5to10pc}",
                    "\\footnotesize{}\\cellcolor{10to20pc}",
                    "\\footnotesize{}\\cellcolor{20to30pc}",
                    "\\footnotesize{}\\cellcolor{masde30pc}",
                    "\\footnotesize{}\\cellcolor{100pc}"
                    ]

    def __init__(self, boundaries: List[List[float]]):

        self.boundaries = boundaries[:]
        self.intervals = Intervals(boundaries)
        self.assigned_values = {interval: latex_value for interval, latex_value
                                in zip(self.intervals, LatexValues.latex_values)}

    def get_latex(self, value: float)-> str:
        return self.assigned_values[self.intervals.get_interval(value)]


def get_latex_values(listainicial: List[List[float]], boundaries: List[float])-> List[List[str]]:
    """
    :param listainicial: a data structure that contains the values used to assign Latex strings
    :param boundaries: the boundaries of the intervals segregating the values
    :return: the appropriate latex string corresponding to a value
             a list of lists that contain the latex_values for mes1-mes5 for each fila in filainicial
    """

    latex_values = LatexValues(boundaries)
    results = []
    for fila in listainicial:
        result = []
        for mes in range(5):
            result.append(latex_values.get_latex(fila[mes]))
        results.append(result)
    return results


if __name__ == '__main__':

    boundaries = [float('-inf'), -25, -10, -5, 0 - EPSILON, 0 + EPSILON, 5, 10, 20, 30, 100, float('inf')]
    test_listainicial = [[0, 22, 43, -200, 1], [12, -4, -12, 110, 41]]
    for result in get_latex_values(test_listainicial, boundaries):
        print(result)

输出:

['\\footnotesize{}\\cellcolor{0pc}', '\\footnotesize{}\\cellcolor{20to30pc}', '\\footnotesize{}\\cellcolor{masde30pc}', '\\footnotesize{}\\cellcolor{menosdem25pc}\\color{white}', '\\footnotesize{}\\cellcolor{0to5pc}']
['\\footnotesize{}\\cellcolor{10to20pc}', '\\footnotesize{}\\cellcolor{m5to0pc}', '\\footnotesize{}\\cellcolor{m25tom10pc}', '\\footnotesize{}\\cellcolor{100pc}', '\\footnotesize{}\\cellcolor{masde30pc}']

推荐阅读