github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/lists/arraylist/arraylist.go (about)

     1  // Package arraylist implements the array list.
     2  //
     3  // Structure is not thread safe.
     4  //
     5  // Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29
     6  package arraylist
     7  
     8  import (
     9  	"encoding/json"
    10  	"fmt"
    11  	"github.com/songzhibin97/go-baseutils/base/bcomparator"
    12  	"github.com/songzhibin97/go-baseutils/structure/lists"
    13  	"reflect"
    14  	"strings"
    15  )
    16  
    17  // Assert List implementation
    18  var _ lists.List[any] = (*List[any])(nil)
    19  
    20  // List holds the elements in a slice
    21  type List[E any] struct {
    22  	elements []E
    23  	size     int
    24  	zero     E
    25  }
    26  
    27  const (
    28  	growthFactor = float32(2.0)  // growth by 100%
    29  	shrinkFactor = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink)
    30  )
    31  
    32  // New instantiates a new list and adds the passed values, if any, to the list
    33  func New[E any](values ...E) *List[E] {
    34  	list := &List[E]{}
    35  	if len(values) > 0 {
    36  		list.Add(values...)
    37  	}
    38  	return list
    39  }
    40  
    41  // Add appends a value at the end of the list
    42  func (l *List[E]) Add(values ...E) {
    43  	l.growBy(len(values))
    44  	for _, value := range values {
    45  		l.elements[l.size] = value
    46  		l.size++
    47  	}
    48  }
    49  
    50  // Get returns the element at index.
    51  // Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false.
    52  func (l *List[E]) Get(index int) (E, bool) {
    53  
    54  	if !l.withinRange(index) {
    55  		return l.zero, false
    56  	}
    57  
    58  	return l.elements[index], true
    59  }
    60  
    61  // Remove removes the element at the given index from the list.
    62  func (l *List[E]) Remove(index int) {
    63  
    64  	if !l.withinRange(index) {
    65  		return
    66  	}
    67  
    68  	l.elements[index] = l.zero                           // cleanup reference
    69  	copy(l.elements[index:], l.elements[index+1:l.size]) // shift to the left by one (slow operation, need ways to optimize this)
    70  	l.size--
    71  
    72  	l.shrink()
    73  }
    74  
    75  // Contains checks if elements (one or more) are present in the set.
    76  // All elements have to be present in the set for the method to return true.
    77  // Performance time complexity of n^2.
    78  // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set.
    79  func (l *List[E]) Contains(values ...E) bool {
    80  
    81  	for _, searchValue := range values {
    82  		found := false
    83  		for index := 0; index < l.size; index++ {
    84  			if reflect.DeepEqual(l.elements[index], searchValue) {
    85  				found = true
    86  				break
    87  			}
    88  		}
    89  		if !found {
    90  			return false
    91  		}
    92  	}
    93  	return true
    94  }
    95  
    96  // Values returns all elements in the list.
    97  func (l *List[E]) Values() []E {
    98  	newElements := make([]E, l.size, l.size)
    99  	copy(newElements, l.elements[:l.size])
   100  	return newElements
   101  }
   102  
   103  // IndexOf returns index of provided element
   104  func (l *List[E]) IndexOf(value E) int {
   105  	if l.size == 0 {
   106  		return -1
   107  	}
   108  	for index, element := range l.elements {
   109  		if reflect.DeepEqual(element, value) {
   110  			return index
   111  		}
   112  	}
   113  	return -1
   114  }
   115  
   116  // Empty returns true if list does not contain any elements.
   117  func (l *List[E]) Empty() bool {
   118  	return l.size == 0
   119  }
   120  
   121  // Size returns number of elements within the list.
   122  func (l *List[E]) Size() int {
   123  	return l.size
   124  }
   125  
   126  // Clear removes all elements from the list.
   127  func (l *List[E]) Clear() {
   128  	l.size = 0
   129  	l.elements = []E{}
   130  }
   131  
   132  // Sort sorts values (in-place) using.
   133  func (l *List[E]) Sort(comparator bcomparator.Comparator[E]) {
   134  	if len(l.elements) < 2 {
   135  		return
   136  	}
   137  	bcomparator.Sort(l.elements[:l.size], comparator)
   138  }
   139  
   140  // Swap swaps the two values at the specified positions.
   141  func (l *List[E]) Swap(i, j int) {
   142  	if l.withinRange(i) && l.withinRange(j) {
   143  		l.elements[i], l.elements[j] = l.elements[j], l.elements[i]
   144  	}
   145  }
   146  
   147  // Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right.
   148  // Does not do anything if position is negative or bigger than list's size
   149  // Note: position equal to list's size is valid, i.e. append.
   150  func (l *List[E]) Insert(index int, values ...E) {
   151  
   152  	if !l.withinRange(index) {
   153  		// Append
   154  		if index == l.size {
   155  			l.Add(values...)
   156  		}
   157  		return
   158  	}
   159  
   160  	ln := len(values)
   161  	l.growBy(ln)
   162  	l.size += ln
   163  	copy(l.elements[index+ln:], l.elements[index:l.size-ln])
   164  	copy(l.elements[index:], values)
   165  }
   166  
   167  // Set the value at specified index
   168  // Does not do anything if position is negative or bigger than list's size
   169  // Note: position equal to list's size is valid, i.e. append.
   170  func (l *List[E]) Set(index int, value E) {
   171  
   172  	if !l.withinRange(index) {
   173  		// Append
   174  		if index == l.size {
   175  			l.Add(value)
   176  		}
   177  		return
   178  	}
   179  
   180  	l.elements[index] = value
   181  }
   182  
   183  // String returns a string representation of container
   184  func (l *List[E]) String() string {
   185  	b := strings.Builder{}
   186  	b.WriteString("ArrayList\n")
   187  	for index, value := range l.elements[:l.size] {
   188  		b.WriteString(fmt.Sprintf("(index:%d value:%v) ", index, value))
   189  	}
   190  	return b.String()
   191  }
   192  
   193  // Check that the index is within bounds of the list
   194  func (l *List[E]) withinRange(index int) bool {
   195  	return index >= 0 && index < l.size
   196  }
   197  
   198  func (l *List[E]) resize(cap int) {
   199  	newElements := make([]E, cap, cap)
   200  	copy(newElements, l.elements)
   201  	l.elements = newElements
   202  }
   203  
   204  // Expand the array if necessary, i.e. capacity will be reached if we add n elements
   205  func (l *List[E]) growBy(n int) {
   206  	// When capacity is reached, grow by a factor of growthFactor and add number of elements
   207  	currentCapacity := cap(l.elements)
   208  	if l.size+n >= currentCapacity {
   209  		newCapacity := int(growthFactor * float32(currentCapacity+n))
   210  		l.resize(newCapacity)
   211  	}
   212  }
   213  
   214  // Shrink the array if necessary, i.e. when size is shrinkFactor percent of current capacity
   215  func (l *List[E]) shrink() {
   216  	if shrinkFactor == 0.0 {
   217  		return
   218  	}
   219  	// Shrink when size is at shrinkFactor * capacity
   220  	currentCapacity := cap(l.elements)
   221  	if l.size <= int(float32(currentCapacity)*shrinkFactor) {
   222  		l.resize(l.size)
   223  	}
   224  }
   225  
   226  func (l *List[E]) UnmarshalJSON(bytes []byte) error {
   227  	err := json.Unmarshal(bytes, &l.elements)
   228  	if err == nil {
   229  		l.size = len(l.elements)
   230  	}
   231  	return err
   232  }
   233  
   234  // MarshalJSON @implements json.Marshaler
   235  func (l *List[E]) MarshalJSON() ([]byte, error) {
   236  	return json.Marshal(l.elements[:l.size])
   237  }