4

のようなソートされたリスト[1.1, 2.2, 3.3]と のような境界値が与えmath.pi*2られた場合、任意の値に最も近い値を返します[0 - math.pi*2)

関数は値のインデックスを返す必要があるため、 returnはwhile return をf(1.2)返し、境界値が与えられた場合は 3.3 よりも 1.1 に近く、 atと returnでラップする必要があります。完全に明確にするために、この関数は下端でもラップアラウンドする必要があるため、 が返されます。0f(2.1)1f(6.0)math.pi*20f(1.0, [5.0, 6.0], bound = math.pi*2)1

使用例は、ラジアン単位の任意の角度を、リスト内の最も近い既存の有効な角度にマップすることです。私はこの種の関数を python で を使って数回書いたことbisectがありますが、コードは常に私の美的感覚を損なうことになります。高度な複雑さとエッジ ケースの数は、関数の直感的な単純さと釣り合っていないように見えます。そこで、効率とエレガンスの両方の点で、誰かが満足のいく実装を思い付くことができるかどうかを尋ねています。

4

3 に答える 3

2

これは、よりエレガントなアプローチです。数直線をラップしてエッジ ケースを排除します。

from bisect import bisect_right

def circular_search(points, bound, value):
    ##
    ## normalize / sort input points to [0, bound)
    points = sorted(list(set([i % bound for i in points])))
    ##
    ## normalize search value to [0, bound)
    value %= bound
    ##
    ## wrap the circle left and right
    ext_points = [i-bound for i in points] + points + [i+bound for i in points]
    ##
    ## identify the "nearest not less than" point; no
    ## edge cases since points always exist above & below
    index = bisect_right(ext_points, value)
    ##
    ## choose the nearest point; will always be either the
    ## index found by bisection, or the next-lower index
    if abs(ext_points[index]-value) >= abs(ext_points[index-1]-value):
        index -= 1
    ##
    ## map index to [0, npoints)
    index %= len(points)
    ##
    ## done
    return points[index]

書かれているように、ポイントがないか、bound==0 のように入力が不安定でない限り機能します。

于 2013-05-19T04:05:33.593 に答える
1

bisectモジュールをベースとして使用します。

from bisect import bisect_left
import math

def f(value, sorted_list, bound=math.pi * 2):
    value %= bound
    index = bisect_left(sorted_list, value)
    if index == 0 or index == len(sorted_list):
        return min((abs(bound + sorted_list[0] - value), 0), (abs(sorted_list[-1] - value), len(sorted_list) - 1))[1]
    return min((index - 1, index), 
        key=lambda i: abs(sorted_list[i] - value) if i >= 0 else float('inf'))

デモ:

>>> sorted_list = [1.1, 2.2, 3.3]
>>> f(1.2, sorted_list)
0
>>> f(2.1, sorted_list)
1
>>> f(6.0, sorted_list)
0
>>> f(5.0, sorted_list)
2
于 2013-05-18T09:45:12.920 に答える
0

最も簡単な方法は、min を使用することです。

def angular_distance(theta_1, theta_2, mod=2*math.pi):
    difference = abs(theta_1 % mod - theta_2 % mod)
    return min(difference, mod - difference)

def nearest_angle(L, theta):
    return min(L, key=lambda theta_1: angular_distance(theta, theta_2))

In [11]: min(L, key=lambda theta: angular_distance(theta, 1))
Out[11]: 1.1

リストのソート性を利用して、bisectモジュールを使用できます。

from bisect import bisect_left

def nearest_angle_b(theta, sorted_list, mod=2*math.pi):
    i1 = bisect_left(sorted_list, theta % mod)
    if i1 == 0:
        i1, i2 = len(sorted_list) - 1, 0
    elif i1 == len(sorted_list):
        i1, i2 = i1 - 1, 0
    else:
        i2 = (i1 + 1) % len(sorted_list)
    return min((angular_distance(theta, L[i], mod), i, L[i])
                 for i in [i1, i2])

リスト内の最も近い距離、インデックス、および角度を返します。

于 2013-05-18T11:06:27.857 に答える