簡體   English   中英

將列表中的值與所有其他值進行比較

[英]Comparing value in a list to all other values

我有一個緯度列表,lats。 我正在嘗試將每個緯度與彼此的緯度進行比較,並找到彼此在 0.01 范圍內的列表項的每個組合。 我目前擁有的代碼就是這樣做的,但是,它還將每個列表值與其自身進行比較。

lats = [79.826, 79.823, 79.855, 79.809]

for i in lats:
    for j in lats:
        if (i - 0.1) <= j <= (i + 0.1):
            print(str(i) +" and "+ str(j))

這將返回 output:

79.826 and 79.826
79.826 and 79.823
79.826 and 79.855
79.826 and 79.809
79.823 and 79.826
79.823 and 79.823
79.823 and 79.855
79.823 and 79.809
79.855 and 79.826
79.855 and 79.823
79.855 and 79.855
79.855 and 79.809
79.809 and 79.826
79.809 and 79.823
79.809 and 79.855
79.809 and 79.809

您正在隱式計算叉積; 你可以寫

for i, j in itertools.product(lats, repeat=2):
    if i - 0.1 <= j <= 1 + 0.1:
        ...

反而。 但是,您想要的是列表中的 2 元素組合

for i, j in itertools.combinations(lats, 2):

對於迭代和生成lats組合,雖然itertools解決方案應該是首選方式,但您可能會對“手動”編碼的某種方式感興趣。 假設您真正想要的只是任意順序的任意兩個lats ,但只是不重復,您可以簡單地逐步限制第二個循環:

for i, x in enumerate(lats):
    for y in lats[i + 1:]:
        ...

此外,當前編寫的條件比所需的條件有點過於復雜。 您真正想要的是兩個值xy小於某個值d分開,因此您可以編寫條件:

(x - d) <= y <= (x + d):

作為:

abs(x - y) <= d

只需添加and i != j

lats = [79.826, 79.823, 79.855, 79.809]

for i in lats:
    for j in lats:
        if (i - 0.1) <= j <= (i + 0.1) and i != j:
            print(str(i) +" and "+ str(j))

輸出:

79.826 and 79.823
79.826 and 79.855
79.826 and 79.809
79.823 and 79.826
79.823 and 79.855
79.823 and 79.809
79.855 and 79.826
79.855 and 79.823
79.855 and 79.809
79.809 and 79.826
79.809 and 79.823
79.809 and 79.855

有一個使用itertools.combinationsabs的簡潔版本

from itertools import combinations
lats = [79.826, 79.823, 79.855, 79.809]
print([c for c in combinations(lats, 2) if abs(c[0] - c[1]) > 0.01])

這使:

[(79.826, 79.855), (79.826, 79.809), (79.823, 79.855), (79.823, 79.809), (79.855, 79.809)]

或使用格式:

from itertools import combinations
lats = [79.826, 79.823, 79.855, 79.809]
close_lats = [c for c in combinations(lats, 2) if abs(c[0] - c[1]) > 0.01]
for combo in close_lats:
    print(f"{combo[0]} and {combo[1]}")

給予:

79.826 and 79.855
79.826 and 79.809
79.823 and 79.855
79.823 and 79.809
79.855 and 79.809

順便說一句,你的問題是你尋找那些在 0.01 以內的,但你的代碼示例似乎在 0.1 以內。

為了提高效率,您可以使用來自itertools的組合迭代器之一(取決於最終結果是什么)和來自數學模塊的isclose

from itertools import permutations
from math import isclose

lats = [79.826, 79.823, 79.855, 79.809]

for l1, l2 in permutations(lats, r=2):
    if isclose(l1, l2, rel_tol=0.01):
        print(f"{l1} and {l2}")

Output:

79.826 and 79.823
79.826 and 79.855
79.826 and 79.809
79.823 and 79.826
79.823 and 79.855
79.823 and 79.809
79.855 and 79.826
79.855 and 79.823
79.855 and 79.809
79.809 and 79.826
79.809 and 79.823
79.809 and 79.855

我認為你應該首先改變你的算法來解決你的問題並避免計算多個緯度(例如79.826 and 79.82379.823 and 79.826 ),然后提高你的代碼性能並將復雜度從O(n^2)降低到O(nlog(n)) (用於對列表進行排序)。

最好對你的 lats 列表進行排序,並設置兩個指針來跟蹤列表的下限和上限,哪些項目在 0.1 的范圍內。

這是代碼:

lats = [79.826, 79.823, 79.855, 79.809]
lats.sort()

i = 0
j = 1
while j < len(lats):
    if lats[j] - lats[i] <= 0.1:
        print(lats[i: j], lats[j])
        j += 1
    else:
        i += 1

Output:

[79.809] 79.823
[79.809, 79.823] 79.826
[79.809, 79.823, 79.826] 79.855

如果您在第一步中對列表進行排序,則可以進行更有效的比較,並且可以在第一次比較失敗時打破內部循環。 因為所有下一個值都會更大。

lats = [79.809, 79.823, 79.826, 79.855]
lats_sorted = sorted(lats)
for index, lat1 in enumerate(lats_sorted[:-1]):
    for lat2 in lats_sorted[index+1:]:
        if (lat2 - lat1 ) < 0.1:
            print(str(lat1) + " and " + str(lat2))
        else:
            break

我對大型列表(5000 個元素)進行了小型運行時比較

def func1(lats):
    pairs = []
    lats_sorted = sorted(lats)
    for index, lat1 in enumerate(lats_sorted[:-1]):
        for lat2 in lats_sorted[index+1:]:
            if lat2 - lat1 <= 0.1:
                pairs.append((lat1, lat2))
            else:
                break
    return pairs


def func2(lats):
    pairs = []
    for i in lats:
        for j in lats:
            if (i - 0.1) <= j <= (i + 0.1):
                pairs.append((i, j))
    return pairs


def func3(lats):
    pairs = []
    for i, j in itertools.combinations(lats, 2):
        if (i - 0.1) <= j <= (i + 0.1):
            pairs.append((i, j))
    return pairs

def func4(lats):
    pairs = []
    for i in lats:
        for j in lats:
            if (i - 0.1) <= j <= (i + 0.1) and i != j:
                pairs.append((i, j))
    return pairs


lats = np.random.randint(0, 100000, 5000) / 1000

print(lats)

func_list = [func1, func2, func3, func4]

for func in func_list:

    start = time.time()
    pairs = func(lats)
    end = time.time()
    print(f"{func.__name__}: time = {end - start} s, pair count = {len(pairs)}")

output 是

[79.759 45.091 19.409 ... 24.691  5.114 64.561]
func1: time = 0.033899545669555664 s, pair count = 24972
func2: time = 6.784521102905273 s, pair count = 55155
func3: time = 2.624063491821289 s, pair count = 25077
func4: time = 6.442306041717529 s, pair count = 49929

表明我提出的算法(func1)比其他算法快得多。 func1 和 func3 (itertools 解決方案)之間的微小計數差異似乎是一個數值精度問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM