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