【问题标题】:Using abs() in a list in Python在 Python 的列表中使用 abs()
【发布时间】:2018-07-20 02:47:39
【问题描述】:

我正在尝试创建一个整数列表,然后对其进行扫描,以找到列表元素减法的最小绝对值。我已经创建了列表,但是在找到最小绝对值的代码中存在问题,因为它显示的结果不正确。我认为它可能在循环期间列表元素的位置。你能帮我找到吗?

例如,当我创建一个列表Α = [2, 7, 5, 9, 3, 1, 2]时,min的结果应该是0,但它是1。

这是我的代码:

min=1000
for i in range (1, N-1):
    for j in range (i+1, N):
        if (abs (A [i-1] - A [j-1])<min):
            min = abs (A [i-1] - A [j-1])
print ("%d" %min)

【问题讨论】:

  • Python 索引从0 开始。 range(1, N - 1) 从 1 开始。
  • 本例中的最小差异为0,因为2-2 == 0.
  • 您要扫描\考虑所有可能的减法吗?
  • N 与列表 (A) 的长度有何关系?我猜您可能排除了对最后一个元素的检查,其中 2-2 将为 0,因为 range(x,y) 不包括 y。
  • @CongMa:这不是 Mike 代码中的错误。他使用A[i-1],因此从 0 开始会引发错误。

标签: python list loops for-loop absolute-value


【解决方案1】:

这就是你要找的东西:

A = [2, 7, 5, 9, 3, 1, 2]

diffs = []
for index1, i in enumerate(A):
     for index2, j in enumerate(A):
         if index1 != index2:
             diffs.append(abs(i-j))             

print(min(diffs))

输出:

0

更新以排除相同项目的减法

【讨论】:

  • 这将从自身中减去每个元素,因此答案始终为零。
  • 好的,但是 OP 没有提到这一点。
  • 我想你可以添加一个内部条件i != j
  • @AndyG,但这会从 OP 提供的数据中排除两个不同的 2s。
  • 是的,我的意思是指索引,您已经调整了代码以包含这些索引。
【解决方案2】:

你可以这样做:

A = [2, 7, 5, 9, 3, 1, 2]

temp = sorted(A)
min_diff = min([abs(i - j) for i, j in zip(temp [:-1], temp [1:])])

print(min_diff)  # -> 0

排序确保产生整体最小差异的元素对(i, j) 是一对连续元素。这使得 您必须执行的检查次数远少于所有可能组合的蛮力方法。


比短路更聪明的东西:

A = [2, 7, 5, 9, 3, 1, 2]


def find_min_diff(my_list):
    if len(set(my_list)) != len(my_list):  # See note 1
        return 0
    else:
        temp = sorted(my_list)
        my_min = float('inf')
        for i, j in zip(temp [:-1], temp [1:]):
            diff = abs(i - j)
            if diff < my_min:
                my_min = diff
        return my_min

print(find_min_diff(A))  # -> 0

注意事项:

1:转换为 set 会删除重复项,因此如果相应的 set 的元素少于原始列表,则意味着至少存在一个重复值。但这必然意味着最小绝对差为 0,我们不必再看下去了。

我敢打赌,对于所有返回 0 的列表来说,这是最快的方法。

【讨论】:

  • 排序本身会产生一些检查;)
  • "因此,您可以只遍历列表一次而不是两次。"不过,我觉得这有点误导,因为这并没有将复杂度从 O(2n) 降低到 O(n),而是从 O(n²/2) 降低到 O(nlogn+n)
  • 是的。第二个版本的时钟频率为 26 µs(与以前的阵列相同)
  • @Piinthesky 为什么这不公平?短路并不是我一个人享受的特权。
  • 让我们总结一下:平均而言,您的解决方案更好,并且列表更短(可能是 numpy 开销)。 Numpy 更适合较长的列表且不重复。
【解决方案3】:

这是一个蛮力解决方案:

from itertools import combinations

A = [2, 7, 5, 9, 3, 1, 2]

min(abs(i-j) for i, j in combinations(A, 2))  # 0

【讨论】:

    【解决方案4】:

    使用 numpy

    import numpy as np
    A = [2, 7, 5, 9, 3, 1, 2]
    v = np.abs(np.diff(np.sort(np.array(A))))
    np.min(v)
    

    输出:0

    或者您可以像这样仅将 numpy 用于差异部分:

    v = min(abs(np.diff(sorted(A))))
    

    【讨论】:

    • 这里的t 是什么?这仅在您事先对输入进行排序时才有效,请参阅 Ev。 Kounis 的回答。
    • 为了让你的代码工作,你应该先排序列表,否则会产生错误的结果。所以应该是 min(abs(np.diff(sorted(t))))
    • 更短,使用np 仅用于diff 部分:min(abs(np.diff(sorted(A))))
    • 也可以,想提出一个完整的numpy解决方案
    【解决方案5】:

    你不应该在内循环中从 j 中减去 1,因为你最终会跳过最后一个 2 的比较。最好在循环范围内进行调整,而不是在循环代码中减1(或不减1):

    A = [2, 7, 5, 9, 3, 1, 2]
    
    N = 7
    
    mint = 1000
    
    for i in range (0, N-1):
        for j in range (i+1, N):
            if (abs(A[i] - A[j]) < mint):
                mint = abs(A[i] - A[j])
                print(i, j)
                print(mint)
    print(mint) # 0
    

    我也避免使用内置函数名称min。


    为避免出现任意、神奇的数字 1000,您可以对 None 执行初始检查:

    A = [2, 7, 5, 9, 3, 1, 2]
    
    N = 7
    
    mint = None
    
    for i in range (0, N-1):
        for j in range (i+1, N):
            if mint is None:
                mint = abs(A[i] - A[j])
            elif (abs(A[i] - A[j]) < mint):
                mint = abs(A[i] - A[j])
                print(i, j)
                print(mint)
    print(mint) # 0
    

    【讨论】:

    • 这不会将A[-2] 与A[-1] 进行比较。您也应该循环使用for i in range(0, N-1) 并使用A[i] 而不是A[i-1]。
    • 如果每个差值都大于 1000 怎么办?
    • 谢谢@tobias_k,我已经更正了。如果范围指定我们将要比较的内容,它也会更清晰,更容易理解。
    • @Piinthesky 从 10,000 开始;) 或以 None 开始并执行初始检查。
    • 从前两个元素的区别开始?
    猜你喜欢
    • 1970-01-01
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 2020-07-14
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多