From 6b5be5f76b23d17be527f8db138c16af8524ab02 Mon Sep 17 00:00:00 2001 From: proost Date: Mon, 14 Sep 2026 17:33:03 +0900 Subject: [PATCH] feat: CompactTrimmed --- theta/union.go | 6 +- theta/update_sketch.go | 31 +++++++ theta/update_sketch_test.go | 175 ++++++++++++++++++++++++++++++++++++ theta/utils.go | 13 +++ theta/utils_test.go | 71 +++++++++++++++ 5 files changed, 291 insertions(+), 5 deletions(-) diff --git a/theta/union.go b/theta/union.go index b501639..7162f8d 100644 --- a/theta/union.go +++ b/theta/union.go @@ -185,11 +185,7 @@ func (u *Union) Result(ordered bool) (*CompactSketch, error) { } } - if uint32(len(entries)) > nominalNum { - internal.QuickSelect(entries, 0, len(entries)-1, int(nominalNum)) - theta = entries[nominalNum] - entries = entries[:nominalNum] - } + entries, theta = trimToNominal(entries, nominalNum, theta) if ordered { slices.Sort(entries) diff --git a/theta/update_sketch.go b/theta/update_sketch.go index a21eae3..bc20592 100644 --- a/theta/update_sketch.go +++ b/theta/update_sketch.go @@ -22,6 +22,7 @@ import ( "fmt" "iter" "math" + "slices" "strings" "github.com/apache/datasketches-go/internal" @@ -415,10 +416,40 @@ func (s *QuickSelectUpdateSketch) All() iter.Seq[uint64] { } } +// Compact converts this sketch to a compact sketch (ordered or unordered). func (s *QuickSelectUpdateSketch) Compact(ordered bool) *CompactSketch { return NewCompactSketch(s, ordered) } +// CompactOrdered converts this sketch to an ordered compact sketch. func (s *QuickSelectUpdateSketch) CompactOrdered() *CompactSketch { return s.Compact(true) } + +// CompactTrimmed converts this sketch to a compact sketch (ordered or unordered) +// reduced to at most the nominal size k. This sketch is not modified. +// +// If this sketch retains more than k entries, theta is lowered to the (k+1)th +// smallest retained hash and only the k entries below it are kept. Otherwise the +// result is the same as Compact. This is equivalent to Trim followed by Compact, +// without mutating this sketch or rebuilding its hash table. +func (s *QuickSelectUpdateSketch) CompactTrimmed(ordered bool) *CompactSketch { + if s.IsEmpty() { + return s.Compact(ordered) + } + + entries := make([]uint64, 0, s.table.numEntries) + for _, entry := range s.table.entries { + if entry != 0 { + entries = append(entries, entry) + } + } + + entries, theta := trimToNominal(entries, uint32(1)<