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  }