github.com/zhongdalu/gf@v1.0.0/g/container/garray/garray_sorted_string.go (about)

     1  // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  
     7  package garray
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/json"
    12  	"math"
    13  	"sort"
    14  	"strings"
    15  
    16  	"github.com/zhongdalu/gf/g/container/gtype"
    17  	"github.com/zhongdalu/gf/g/internal/rwmutex"
    18  	"github.com/zhongdalu/gf/g/util/gconv"
    19  	"github.com/zhongdalu/gf/g/util/grand"
    20  )
    21  
    22  // It's using increasing order in default.
    23  type SortedStringArray struct {
    24  	mu         *rwmutex.RWMutex
    25  	array      []string
    26  	unique     *gtype.Bool             // Whether enable unique feature(false)
    27  	comparator func(v1, v2 string) int // Comparison function(it returns -1: v1 < v2; 0: v1 == v2; 1: v1 > v2)
    28  }
    29  
    30  // NewSortedStringArray creates and returns an empty sorted array.
    31  // The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
    32  // which is false in default.
    33  func NewSortedStringArray(unsafe ...bool) *SortedStringArray {
    34  	return NewSortedStringArraySize(0, unsafe...)
    35  }
    36  
    37  // NewSortedStringArraySize create and returns an sorted array with given size and cap.
    38  // The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
    39  // which is false in default.
    40  func NewSortedStringArraySize(cap int, unsafe ...bool) *SortedStringArray {
    41  	return &SortedStringArray{
    42  		mu:     rwmutex.New(unsafe...),
    43  		array:  make([]string, 0, cap),
    44  		unique: gtype.NewBool(),
    45  		comparator: func(v1, v2 string) int {
    46  			return strings.Compare(v1, v2)
    47  		},
    48  	}
    49  }
    50  
    51  // NewSortedStringArrayFrom creates and returns an sorted array with given slice <array>.
    52  // The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
    53  // which is false in default.
    54  func NewSortedStringArrayFrom(array []string, unsafe ...bool) *SortedStringArray {
    55  	a := NewSortedStringArraySize(0, unsafe...)
    56  	a.array = array
    57  	sort.Strings(a.array)
    58  	return a
    59  }
    60  
    61  // NewSortedStringArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
    62  // The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
    63  // which is false in default.
    64  func NewSortedStringArrayFromCopy(array []string, unsafe ...bool) *SortedStringArray {
    65  	newArray := make([]string, len(array))
    66  	copy(newArray, array)
    67  	return NewSortedStringArrayFrom(newArray, unsafe...)
    68  }
    69  
    70  // SetArray sets the underlying slice array with the given <array>.
    71  func (a *SortedStringArray) SetArray(array []string) *SortedStringArray {
    72  	a.mu.Lock()
    73  	defer a.mu.Unlock()
    74  	a.array = array
    75  	sort.Strings(a.array)
    76  	return a
    77  }
    78  
    79  // Sort sorts the array in increasing order.
    80  // The parameter <reverse> controls whether sort
    81  // in increasing order(default) or decreasing order.
    82  func (a *SortedStringArray) Sort() *SortedStringArray {
    83  	a.mu.Lock()
    84  	defer a.mu.Unlock()
    85  	sort.Strings(a.array)
    86  	return a
    87  }
    88  
    89  // Add adds one or multiple values to sorted array, the array always keeps sorted.
    90  func (a *SortedStringArray) Add(values ...string) *SortedStringArray {
    91  	if len(values) == 0 {
    92  		return a
    93  	}
    94  	a.mu.Lock()
    95  	defer a.mu.Unlock()
    96  	for _, value := range values {
    97  		index, cmp := a.binSearch(value, false)
    98  		if a.unique.Val() && cmp == 0 {
    99  			continue
   100  		}
   101  		if index < 0 {
   102  			a.array = append(a.array, value)
   103  			continue
   104  		}
   105  		if cmp > 0 {
   106  			index++
   107  		}
   108  		rear := append([]string{}, a.array[index:]...)
   109  		a.array = append(a.array[0:index], value)
   110  		a.array = append(a.array, rear...)
   111  	}
   112  	return a
   113  }
   114  
   115  // Get returns the value of the specified index,
   116  // the caller should notice the boundary of the array.
   117  func (a *SortedStringArray) Get(index int) string {
   118  	a.mu.RLock()
   119  	defer a.mu.RUnlock()
   120  	value := a.array[index]
   121  	return value
   122  }
   123  
   124  // Remove removes an item by index.
   125  func (a *SortedStringArray) Remove(index int) string {
   126  	a.mu.Lock()
   127  	defer a.mu.Unlock()
   128  	// Determine array boundaries when deleting to improve deletion efficiency.
   129  	if index == 0 {
   130  		value := a.array[0]
   131  		a.array = a.array[1:]
   132  		return value
   133  	} else if index == len(a.array)-1 {
   134  		value := a.array[index]
   135  		a.array = a.array[:index]
   136  		return value
   137  	}
   138  	// If it is a non-boundary delete,
   139  	// it will involve the creation of an array,
   140  	// then the deletion is less efficient.
   141  	value := a.array[index]
   142  	a.array = append(a.array[:index], a.array[index+1:]...)
   143  	return value
   144  }
   145  
   146  // PopLeft pops and returns an item from the beginning of array.
   147  func (a *SortedStringArray) PopLeft() string {
   148  	a.mu.Lock()
   149  	defer a.mu.Unlock()
   150  	value := a.array[0]
   151  	a.array = a.array[1:]
   152  	return value
   153  }
   154  
   155  // PopRight pops and returns an item from the end of array.
   156  func (a *SortedStringArray) PopRight() string {
   157  	a.mu.Lock()
   158  	defer a.mu.Unlock()
   159  	index := len(a.array) - 1
   160  	value := a.array[index]
   161  	a.array = a.array[:index]
   162  	return value
   163  }
   164  
   165  // PopRand randomly pops and return an item out of array.
   166  func (a *SortedStringArray) PopRand() string {
   167  	return a.Remove(grand.Intn(len(a.array)))
   168  }
   169  
   170  // PopRands randomly pops and returns <size> items out of array.
   171  func (a *SortedStringArray) PopRands(size int) []string {
   172  	a.mu.Lock()
   173  	defer a.mu.Unlock()
   174  	if size > len(a.array) {
   175  		size = len(a.array)
   176  	}
   177  	array := make([]string, size)
   178  	for i := 0; i < size; i++ {
   179  		index := grand.Intn(len(a.array))
   180  		array[i] = a.array[index]
   181  		a.array = append(a.array[:index], a.array[index+1:]...)
   182  	}
   183  	return array
   184  }
   185  
   186  // PopLefts pops and returns <size> items from the beginning of array.
   187  func (a *SortedStringArray) PopLefts(size int) []string {
   188  	a.mu.Lock()
   189  	defer a.mu.Unlock()
   190  	length := len(a.array)
   191  	if size > length {
   192  		size = length
   193  	}
   194  	value := a.array[0:size]
   195  	a.array = a.array[size:]
   196  	return value
   197  }
   198  
   199  // PopRights pops and returns <size> items from the end of array.
   200  func (a *SortedStringArray) PopRights(size int) []string {
   201  	a.mu.Lock()
   202  	defer a.mu.Unlock()
   203  	index := len(a.array) - size
   204  	if index < 0 {
   205  		index = 0
   206  	}
   207  	value := a.array[index:]
   208  	a.array = a.array[:index]
   209  	return value
   210  }
   211  
   212  // Range picks and returns items by range, like array[start:end].
   213  // Notice, if in concurrent-safe usage, it returns a copy of slice;
   214  // else a pointer to the underlying data.
   215  //
   216  // If <end> is negative, then the offset will start from the end of array.
   217  // If <end> is omitted, then the sequence will have everything from start up
   218  // until the end of the array.
   219  func (a *SortedStringArray) Range(start int, end ...int) []string {
   220  	a.mu.RLock()
   221  	defer a.mu.RUnlock()
   222  	offsetEnd := len(a.array)
   223  	if len(end) > 0 && end[0] < offsetEnd {
   224  		offsetEnd = end[0]
   225  	}
   226  	if start > offsetEnd {
   227  		return nil
   228  	}
   229  	if start < 0 {
   230  		start = 0
   231  	}
   232  	array := ([]string)(nil)
   233  	if a.mu.IsSafe() {
   234  		array = make([]string, offsetEnd-start)
   235  		copy(array, a.array[start:offsetEnd])
   236  	} else {
   237  		array = a.array[start:offsetEnd]
   238  	}
   239  	return array
   240  }
   241  
   242  // SubSlice returns a slice of elements from the array as specified
   243  // by the <offset> and <size> parameters.
   244  // If in concurrent safe usage, it returns a copy of the slice; else a pointer.
   245  //
   246  // If offset is non-negative, the sequence will start at that offset in the array.
   247  // If offset is negative, the sequence will start that far from the end of the array.
   248  //
   249  // If length is given and is positive, then the sequence will have up to that many elements in it.
   250  // If the array is shorter than the length, then only the available array elements will be present.
   251  // If length is given and is negative then the sequence will stop that many elements from the end of the array.
   252  // If it is omitted, then the sequence will have everything from offset up until the end of the array.
   253  //
   254  // Any possibility crossing the left border of array, it will fail.
   255  func (a *SortedStringArray) SubSlice(offset int, length ...int) []string {
   256  	a.mu.RLock()
   257  	defer a.mu.RUnlock()
   258  	size := len(a.array)
   259  	if len(length) > 0 {
   260  		size = length[0]
   261  	}
   262  	if offset > len(a.array) {
   263  		return nil
   264  	}
   265  	if offset < 0 {
   266  		offset = len(a.array) + offset
   267  		if offset < 0 {
   268  			return nil
   269  		}
   270  	}
   271  	if size < 0 {
   272  		offset += size
   273  		size = -size
   274  		if offset < 0 {
   275  			return nil
   276  		}
   277  	}
   278  	end := offset + size
   279  	if end > len(a.array) {
   280  		end = len(a.array)
   281  		size = len(a.array) - offset
   282  	}
   283  	if a.mu.IsSafe() {
   284  		s := make([]string, size)
   285  		copy(s, a.array[offset:])
   286  		return s
   287  	} else {
   288  		return a.array[offset:end]
   289  	}
   290  }
   291  
   292  // Sum returns the sum of values in an array.
   293  func (a *SortedStringArray) Sum() (sum int) {
   294  	a.mu.RLock()
   295  	defer a.mu.RUnlock()
   296  	for _, v := range a.array {
   297  		sum += gconv.Int(v)
   298  	}
   299  	return
   300  }
   301  
   302  // Len returns the length of array.
   303  func (a *SortedStringArray) Len() int {
   304  	a.mu.RLock()
   305  	length := len(a.array)
   306  	a.mu.RUnlock()
   307  	return length
   308  }
   309  
   310  // Slice returns the underlying data of array.
   311  // Notice, if in concurrent-safe usage, it returns a copy of slice;
   312  // else a pointer to the underlying data.
   313  func (a *SortedStringArray) Slice() []string {
   314  	array := ([]string)(nil)
   315  	if a.mu.IsSafe() {
   316  		a.mu.RLock()
   317  		defer a.mu.RUnlock()
   318  		array = make([]string, len(a.array))
   319  		copy(array, a.array)
   320  	} else {
   321  		array = a.array
   322  	}
   323  	return array
   324  }
   325  
   326  // Contains checks whether a value exists in the array.
   327  func (a *SortedStringArray) Contains(value string) bool {
   328  	return a.Search(value) != -1
   329  }
   330  
   331  // Search searches array by <value>, returns the index of <value>,
   332  // or returns -1 if not exists.
   333  func (a *SortedStringArray) Search(value string) (index int) {
   334  	if i, r := a.binSearch(value, true); r == 0 {
   335  		return i
   336  	}
   337  	return -1
   338  }
   339  
   340  // Binary search.
   341  // It returns the last compared index and the result.
   342  // If <result> equals to 0, it means the value at <index> is equals to <value>.
   343  // If <result> lesser than 0, it means the value at <index> is lesser than <value>.
   344  // If <result> greater than 0, it means the value at <index> is greater than <value>.
   345  func (a *SortedStringArray) binSearch(value string, lock bool) (index int, result int) {
   346  	if len(a.array) == 0 {
   347  		return -1, -2
   348  	}
   349  	if lock {
   350  		a.mu.RLock()
   351  		defer a.mu.RUnlock()
   352  	}
   353  	min := 0
   354  	max := len(a.array) - 1
   355  	mid := 0
   356  	cmp := -2
   357  	for min <= max {
   358  		mid = int((min + max) / 2)
   359  		cmp = a.comparator(value, a.array[mid])
   360  		switch {
   361  		case cmp < 0:
   362  			max = mid - 1
   363  		case cmp > 0:
   364  			min = mid + 1
   365  		default:
   366  			return mid, cmp
   367  		}
   368  	}
   369  	return mid, cmp
   370  }
   371  
   372  // SetUnique sets unique mark to the array,
   373  // which means it does not contain any repeated items.
   374  // It also do unique check, remove all repeated items.
   375  func (a *SortedStringArray) SetUnique(unique bool) *SortedStringArray {
   376  	oldUnique := a.unique.Val()
   377  	a.unique.Set(unique)
   378  	if unique && oldUnique != unique {
   379  		a.Unique()
   380  	}
   381  	return a
   382  }
   383  
   384  // Unique uniques the array, clear repeated items.
   385  func (a *SortedStringArray) Unique() *SortedStringArray {
   386  	a.mu.Lock()
   387  	i := 0
   388  	for {
   389  		if i == len(a.array)-1 {
   390  			break
   391  		}
   392  		if a.comparator(a.array[i], a.array[i+1]) == 0 {
   393  			a.array = append(a.array[:i+1], a.array[i+1+1:]...)
   394  		} else {
   395  			i++
   396  		}
   397  	}
   398  	a.mu.Unlock()
   399  	return a
   400  }
   401  
   402  // Clone returns a new array, which is a copy of current array.
   403  func (a *SortedStringArray) Clone() (newArray *SortedStringArray) {
   404  	a.mu.RLock()
   405  	array := make([]string, len(a.array))
   406  	copy(array, a.array)
   407  	a.mu.RUnlock()
   408  	return NewSortedStringArrayFrom(array, !a.mu.IsSafe())
   409  }
   410  
   411  // Clear deletes all items of current array.
   412  func (a *SortedStringArray) Clear() *SortedStringArray {
   413  	a.mu.Lock()
   414  	if len(a.array) > 0 {
   415  		a.array = make([]string, 0)
   416  	}
   417  	a.mu.Unlock()
   418  	return a
   419  }
   420  
   421  // LockFunc locks writing by callback function <f>.
   422  func (a *SortedStringArray) LockFunc(f func(array []string)) *SortedStringArray {
   423  	a.mu.Lock()
   424  	defer a.mu.Unlock()
   425  	f(a.array)
   426  	return a
   427  }
   428  
   429  // RLockFunc locks reading by callback function <f>.
   430  func (a *SortedStringArray) RLockFunc(f func(array []string)) *SortedStringArray {
   431  	a.mu.RLock()
   432  	defer a.mu.RUnlock()
   433  	f(a.array)
   434  	return a
   435  }
   436  
   437  // Merge merges <array> into current array.
   438  // The parameter <array> can be any garray or slice type.
   439  // The difference between Merge and Append is Append supports only specified slice type,
   440  // but Merge supports more parameter types.
   441  func (a *SortedStringArray) Merge(array interface{}) *SortedStringArray {
   442  	switch v := array.(type) {
   443  	case *Array:
   444  		a.Add(gconv.Strings(v.Slice())...)
   445  	case *IntArray:
   446  		a.Add(gconv.Strings(v.Slice())...)
   447  	case *StringArray:
   448  		a.Add(gconv.Strings(v.Slice())...)
   449  	case *SortedArray:
   450  		a.Add(gconv.Strings(v.Slice())...)
   451  	case *SortedIntArray:
   452  		a.Add(gconv.Strings(v.Slice())...)
   453  	case *SortedStringArray:
   454  		a.Add(gconv.Strings(v.Slice())...)
   455  	default:
   456  		a.Add(gconv.Strings(array)...)
   457  	}
   458  	return a
   459  }
   460  
   461  // Chunk splits an array into multiple arrays,
   462  // the size of each array is determined by <size>.
   463  // The last chunk may contain less than size elements.
   464  func (a *SortedStringArray) Chunk(size int) [][]string {
   465  	if size < 1 {
   466  		return nil
   467  	}
   468  	a.mu.RLock()
   469  	defer a.mu.RUnlock()
   470  	length := len(a.array)
   471  	chunks := int(math.Ceil(float64(length) / float64(size)))
   472  	var n [][]string
   473  	for i, end := 0, 0; chunks > 0; chunks-- {
   474  		end = (i + 1) * size
   475  		if end > length {
   476  			end = length
   477  		}
   478  		n = append(n, a.array[i*size:end])
   479  		i++
   480  	}
   481  	return n
   482  }
   483  
   484  // Rand randomly returns one item from array(no deleting).
   485  func (a *SortedStringArray) Rand() string {
   486  	a.mu.RLock()
   487  	defer a.mu.RUnlock()
   488  	return a.array[grand.Intn(len(a.array))]
   489  }
   490  
   491  // Rands randomly returns <size> items from array(no deleting).
   492  func (a *SortedStringArray) Rands(size int) []string {
   493  	a.mu.RLock()
   494  	defer a.mu.RUnlock()
   495  	if size > len(a.array) {
   496  		size = len(a.array)
   497  	}
   498  	n := make([]string, size)
   499  	for i, v := range grand.Perm(len(a.array)) {
   500  		n[i] = a.array[v]
   501  		if i == size-1 {
   502  			break
   503  		}
   504  	}
   505  	return n
   506  }
   507  
   508  // Join joins array elements with a string <glue>.
   509  func (a *SortedStringArray) Join(glue string) string {
   510  	a.mu.RLock()
   511  	defer a.mu.RUnlock()
   512  	buffer := bytes.NewBuffer(nil)
   513  	for k, v := range a.array {
   514  		buffer.WriteString(gconv.String(v))
   515  		if k != len(a.array)-1 {
   516  			buffer.WriteString(glue)
   517  		}
   518  	}
   519  	return buffer.String()
   520  }
   521  
   522  // CountValues counts the number of occurrences of all values in the array.
   523  func (a *SortedStringArray) CountValues() map[string]int {
   524  	m := make(map[string]int)
   525  	a.mu.RLock()
   526  	defer a.mu.RUnlock()
   527  	for _, v := range a.array {
   528  		m[v]++
   529  	}
   530  	return m
   531  }
   532  
   533  // String returns current array as a string.
   534  func (a *SortedStringArray) String() string {
   535  	a.mu.RLock()
   536  	defer a.mu.RUnlock()
   537  	jsonContent, _ := json.Marshal(a.array)
   538  	return string(jsonContent)
   539  }
   540  
   541  // MarshalJSON implements the interface MarshalJSON for json.Marshal.
   542  func (a *SortedStringArray) MarshalJSON() ([]byte, error) {
   543  	a.mu.RLock()
   544  	defer a.mu.RUnlock()
   545  	return json.Marshal(a.array)
   546  }