我怎样才能不重复写类似的代码?

How can I not repeat writing similar code?

我有两个非常相似的函数,除了条件相反之外,几乎是一模一样的。我想遵循 DRY 模式,但我之前在某处读到过,将布尔值传递给函数以改变行为是一种不好的做法(因为它很难维护)。在这里我编写干净且非重复代码的最佳选择是什么?谢谢

def find_upper_tangent(left, right):
    l_idx = get_rightmost(left)
    r_idx = get_leftmost(right)
    upper_tangent_left = False
    upper_tangent_right = False
    prev_slope = get_slope(left[l_idx], right[r_idx])
    while not upper_tangent_left or not upper_tangent_right:
        while not upper_tangent_left:
            # move counter clockwise
            next_slope = get_slope(left[(l_idx - 1) % len(left)], right[r_idx])
            if next_slope < prev_slope:
                l_idx = (l_idx - 1) % len(left)
                prev_slope = next_slope
                upper_tangent_right = False
            else:
                upper_tangent_left = True
        while not upper_tangent_right:
            # move clockwise
            next_slope = get_slope(left[l_idx], right[(r_idx + 1) % len(right)])
            if next_slope > prev_slope:
                r_idx = (r_idx + 1) % len(right)
                prev_slope = next_slope
                upper_tangent_left = False
            else:
                upper_tangent_right = True
    return l_idx, r_idx


def find_lower_tangent(left, right):
    l_idx = get_rightmost(left)
    r_idx = get_leftmost(right)
    lower_tangent_left = False
    lower_tangent_right = False
    prev_slope = get_slope(left[l_idx], right[r_idx])
    while not lower_tangent_left or not lower_tangent_right:
        while not lower_tangent_left:
            # move clockwise
            next_slope = get_slope(left[(l_idx + 1) % len(left)], right[r_idx])
            if next_slope > prev_slope:
                l_idx = (l_idx + 1) % len(left)
                prev_slope = next_slope
                lower_tangent_right = False
            else:
                lower_tangent_left = True    
        while not lower_tangent_right:
            # move counter clockwise
            next_slope = get_slope(left[l_idx], right[(r_idx - 1) % len(right)])
            if next_slope < prev_slope:
                r_idx = (r_idx - 1) % len(right)
                prev_slope = next_slope
                lower_tangent_left = False
            else:
                lower_tangent_right = True
    return l_idx, r_idx

我认为类似的东西应该做同样的计算:

def find_upper_tangent(left, right):
    return find_tangent(left, right, -1)

def find_lower_tangent(left, right):
    return find_tangent(left, right, 1)

def find_tangent(left, right, shift_val):
    l_idx = get_rightmost(left)
    r_idx = get_leftmost(right)

    prev_slope = get_slope(left[l_idx], right[r_idx])
    next_slope = prev_slope

    while compare(next_slope, prev_slope) == (shift_val / shift_val):
        # move counter clockwise
        prev_slope = next_slope
        l_idx = (l_idx + shift_val) % len(left)
        next_slope = get_slope(left[l_idx], right[r_idx])

    while compare(next_slope, prev_slope) == (shift_val / -shift_val)):
        # move clockwise
        prev_slope = next_slope
        r_idx = (r_idx - shift_val) % len(right)
        next_slope = get_slope(left[l_idx], right[r_idx])

    return l_idx, r_idx

def compare(v1, v2):
    return -1 if v1 > v2 else 0 if v1 == v2 else 1

在我看来,这比传递一个标志要好,因为您传递的是一个有意义并用于计算的值。

我是怎么来到这里的

既然你要求的是一种方法,我将尝试描述我是如何找到这个解决方案的:

  1. 简化代码

    • 外部 while 循环仅 运行 一次,因此可以将其删除。这是关键,因为它消除了循环条件变量的一种使用。
    • 然后我们看到每个剩余的 while 循环都有一个 else 子句,它只设置循环条件变量。相反,我们可以简单地使用 if 条件作为循环条件。这消除了布尔变量的需要并减少了代码路径的数量——这两个都是简化代码的伟大目标!
    • 现在我们看到我们需要更改操作顺序。在计算新值之前,我们需要保存 next_slope 的值。我们还对新指数进行了两次计算。一次获取斜率,一次保存值。相反,我们可以计算新的索引,然后在斜率计算中使用它。
  2. 注意代码中的相似之处

    • 请注意,在两个循环中,我们移动了索引,但方向相反。我们可以添加一个移位值参数并编写代码,即使值相同,移位的方向也会改变。
    • 注意上下切线计算中左右循环的比较方向不同。为了解决这个问题,我们可以编写一个函数来比较两个事物,returns 如果第一个更大则为 -1,如果第二个更大则为 1,如果它们相同则为 0。
    • 现在我们有了移位值,它会根据我们是在寻找上限还是下限而具有不同的符号,我们可以使用它来翻转 while 条件的方向。

我尚未验证此解决方案是否有效 - 如果您想 post 一些测试数据和预期结果,那就太好了!