単一のリストに対してこれを行う関数を作成します。
>>> compact([6.23234121,6.23246575], tol=.01)
[6.23234121]
その後、ネストされた構造で動作させることができます[compact(l) for l in lst]
。
これらの各メソッドは、リスト内でそれに近いものを持たない最初の要素を保持します。@DSM の例では、[0, 0.005, 0.01, 0.015, 0.02]
それらはすべて返され[0, 0.0.15]
ます (または、に切り替え>
た場合>=
は[0, 0.01, 0.02]
)。何か違うものが必要な場合は、それが何であるかをより慎重に定義する必要があります。
まず、デビッドの答えに似た簡単なアプローチ。これは O(n^2) です:
def compact(lst, tol):
new = []
for el in lst:
if all(abs(el - x) > tol for x in new):
new.append(el)
return compact
3 要素リストでは、これはまったく問題ありません。ただし、300 万要素のリストでそれを実行したい場合は、それでは不十分です。別のことを試してみましょう:
import collections
import math
def compact(lst, tol):
round_digits = -math.log10(tol) - 1
seen = collections.defaultdict(set)
new = []
for el in lst:
rounded = round(seen, round_digits)
if all(abs(el - x) > tol for x in seen[rounded]):
seen[rounded].add(el)
new.append(el)
return new
もしあなたtol
がなら0.01
、それround_digits
は 1です。次に が表示されたら、それを に丸め、インデックスで検索します。インデックスには、検索している数値に含まれる可能性のあるすべての数値が含まれている必要があります。次に、これらの数値までの距離を確認する必要がありますが、リスト全体ではなく、そのインデックス ビンにあるごく少数の数値についてのみ確認する必要があります。6.23234121
seen
6.2
6.23246575
6.2
tol
このアプローチは O(nk) です。ここで、k は 1 つのビン内に収まる要素の平均数です。k << n の場合にのみ役立ちます (通常はそうですが、使用している数値の分布に依存しますtol
)。また、他のアプローチよりもおそらく 2 倍以上のメモリを使用することに注意してください。これは、非常に大きなリストでは問題になる可能性があります。
もう 1 つのオプションは、最初にリストをソートすることです。その場合は、前後の要素を調べて競合を確認するだけで済みます。