diff --git a/tablex.lua b/tablex.lua index 7f75872..3ef1031 100644 --- a/tablex.lua +++ b/tablex.lua @@ -48,25 +48,68 @@ function tablex.unshift(t, v) return t end +function tablex.is_sorted(t) + local sorted = true + for i = 1, #t - 1 do + if t[i] > t[i + 1] then + sorted = false + break + end + end + return sorted +end + --insert to the first position before the first larger element in the table --if this is used on an already sorted table, the table will remain sorted and not need re-sorting --todo: make it do binary search rather than linear to improve performance --return the table for possible chaining function tablex.insert_sorted(t, v, less) local inserted = false - for i = 1, #t do - if less(v, t[i]) then - table.insert(t, i, v) + + -- to use binary search is necessary as precondition that + -- the table is sorted + if not tablex.is_sorted(t) then + for i = 1, #t do + if less(v, t[i]) then + table.insert(t, i, v) + inserted = true + break + end + end + if not inserted then + table.insert(t, v) + end + return t + end + + local l = 1 + local r = #t + + if r < l then + table.insert(t,v) + return t + end + + + while l <= r do + local mid = math.floor(l + (r - l) / 2) + if (less(v, t[mid]) or v == t[mid]) and (mid == 1 or less(t[mid - 1], v) or t[mid - 1] == v) then + table.insert(t, mid, v) inserted = true break + elseif less(t[mid], v) then + l = mid + 1 + elseif less(v, t[mid - 1]) then + r = mid - 1 end end + if not inserted then - table.insert(t, v) + table.insert(t, l, v) end + return t end - --find the index in a sequential table that a resides at --or nil if nothing was found function tablex.index_of(t, a)