github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/sort/sortmapx/main.go (about) 1 // package sortmapx sorts maps into 2 // an ordered *persistent* slice of KV-structs; 3 // it also constructs slices of dense key ranges 4 // with partial sums of values; see tests; 5 // before using, consider the simpler sortmap.StringKeysToSortedArray() 6 // or sortmap.StringKeysToSortedArray(); 7 // before using, consider the simpler sortmap.SortByCnt(map[string]int). 8 // It is useful for with unpredictable *sparse* long tails. 9 // This package only adds value, if we want *repeated* access to 10 // specific sort offsets, or to min and max values. 11 // The package furthermore *flattens* the map to a fully ranged array 12 // of offsets. 13 package sortmapx 14 15 import "sort" 16 17 type sortedKV struct { 18 K, V int 19 } 20 21 type SortedMapInt2Int struct { 22 m map[int]int 23 dirty bool 24 sortedKeys []int // statified partially: [sortIndex][key] 25 sKV []sortedKV // statified fully: [sortIndex][key][val] 26 } 27 28 func (m *SortedMapInt2Int) updateSort() { 29 keys := make([]int, len(m.m)) 30 i := 0 31 for key, _ := range m.m { 32 keys[i] = key 33 i++ 34 } 35 sort.Ints(keys) 36 m.sortedKeys = keys 37 } 38 39 func NewSortedMapInt2Int() (sm SortedMapInt2Int) { 40 sm = SortedMapInt2Int{} 41 sm.m = make(map[int]int) 42 sm.sortedKeys = make([]int, 0) 43 return 44 } 45 46 func (m *SortedMapInt2Int) Set(k, v int) { 47 m.m[k] = v 48 m.dirty = true // that's why m is pointer *SortedMapInt2Int 49 } 50 func (m *SortedMapInt2Int) Inc(k int) { 51 m.m[k]++ 52 m.dirty = true // that's why m is pointer *SortedMapInt2Int 53 } 54 func (m SortedMapInt2Int) Get(k int) (v int, ok bool) { 55 v, ok = m.m[k] 56 return 57 } 58 59 func (m SortedMapInt2Int) MaxKey() int { 60 if len(m.m) == 0 { 61 panic("Max of empty map has no answer") 62 } 63 if m.dirty { 64 m.updateSort() 65 m.dirty = false 66 } 67 lastIdx := len(m.sortedKeys) - 1 68 return m.sortedKeys[lastIdx] 69 } 70 71 func (m SortedMapInt2Int) MinKey() int { 72 if len(m.m) == 0 { 73 panic("Min of empty map has no answer") 74 } 75 if m.dirty { 76 m.updateSort() 77 m.dirty = false 78 } 79 return m.sortedKeys[0] 80 } 81 82 func (m *SortedMapInt2Int) SortedKeys() []int { 83 if m.dirty { 84 m.updateSort() 85 m.dirty = false 86 } 87 return m.sortedKeys 88 } 89 90 // Returns the statified sorted map: [Sortindex][Key][Value] 91 // This could also be achieved by iterating SortedKeys() and calling Get(v). 92 // It may be worthwhile for external packages to save Get() calls and for repetitive iterations 93 func (m *SortedMapInt2Int) SortedKV() []sortedKV { 94 if m.dirty { 95 m.updateSort() 96 m.dirty = false 97 } 98 m.sKV = make([]sortedKV, len(m.m)) 99 for k, v := range m.sortedKeys { 100 m.sKV[k] = sortedKV{v, m.m[v]} 101 } 102 return m.sKV 103 } 104 105 // Again: [Sortindex][Key][Value] 106 // This time: Sortindex exists also for *empty* keys 107 // and for keys [0...MinKey) 108 // Motivation: In case we have some sorted data (outside), 109 // then we do not want to iterate to find a specific value. 110 // Instead we want to *pinpoint* a distinct instance. 111 // Therefore we need the offsets to these instances. 112 // These offsets can be seen as *partial sums* 113 func (m SortedMapInt2Int) SortedPartialSums() ([]sortedKV, []int) { 114 groundedMin := m.MinKey() 115 if groundedMin > 0 { 116 groundedMin = 0 117 } 118 skv := make([]sortedKV, m.MaxKey()-groundedMin+1) 119 flattened := make([]int, len(skv)) 120 cnt := 0 121 j := 0 122 for i := groundedMin; i < m.MaxKey()+1; i++ { 123 if v2, ok := m.Get(i); ok { 124 cnt += v2 125 } 126 skv[j].K = i 127 skv[j].V = cnt 128 129 flattened[j] = cnt 130 131 j++ 132 } 133 return skv, flattened 134 }