連続したタイムスタンプの配列があります。開始時間と終了時間の間にある配列のサブセットを取得する必要があります。簡単な例は次のようになります。
timestamps = [ 5,7,12,13,15,23 ];
startTime = 6;
endTime = 18;
上記の例で、 と の間にある最初と最後のタイムスタンプのインデックスを見つける最も効率的な方法は何startTime
ですかendTime
?
正しいスクリプトは、インデックス 1 と 4 を検出して返します ( timestamps[1], timestamps[4]
)
配列をループして比較することもできますが、もっと効率的な方法はありますか?
編集::私の解決策 - 二分探索:
(コーヒースクリプト)
# Search ordered array for timestamps falling between 'start' & 'end'
getRangeBorderIndexes = (stack, start, end) ->
ar = []
ar[0] = getBorder( stack, start, "left" )
ar[1] = getBorder( stack, end, "right" )
return ar
# Use bisection (binary search) to find leftmost or rightmost border indexes
getBorder = (stack, value, side ) ->
mod1 = if side == "left" then 0 else -1
mod2 = if side == "left" then 1 else 0
startIndex = 0
stopIndex = stack.length - 1
middle = Math.floor( (stopIndex+startIndex)/2 )
while stack[middle] != value && startIndex < stopIndex
if value < stack[middle]
if value > stack[middle - 1] then return middle + mod1
stopIndex = middle - 1
else if value > stack[middle]
if value < stack[middle + 1] then return middle + mod2
startIndex = middle + 1
middle = Math.floor( (stopIndex+startIndex)/2 )
return if stack[middle] != value then -1 else middle
timestamps = [ 5,7,12,13,15,23 ]
startTime = 6
endTime = 18
getRangeBorderIndexes( timestamps, startTime, endTime) # returns [1,5]
@kennebec と @Shanimal は、特に配列のサブセットを取得するための非常にシンプルな方法が必要な場合に、素晴らしい反応を示しました。ただし、サブ配列全体ではなく、サブ配列のインデックスが必要でした。私はいくつかのテストを行いましたが、上記の例では、1,000 万のエントリを持つ配列であっても、サブ配列の境界を見つけるのに一貫して約 7 ミリ秒かかります!
正しい方向に向けてくれた@voithosに感謝します。上記のソリューションを作成するために、このコードも変更しました。