// Copyright 2021 dudaodong@gmail.com. All rights reserved. // Use of this source code is governed by MIT license // Package datastructure contains some data structure. list is a linear table, implemented with slice. package datastructure import ( "reflect" "github.com/duke-git/lancet/v2/iterator" ) // List is a linear table, implemented with slice. type List[T any] struct { data []T } // NewList return a pointer of List. func NewList[T any](data []T) *List[T] { return &List[T]{data: data} } // Data return list data. func (l *List[T]) Data() []T { return l.data } // ValueOf return the value pointer at index of list data. func (l *List[T]) ValueOf(index int) (*T, bool) { if index < 0 || index >= len(l.data) { return nil, false } return &l.data[index], true } // IndexOf returns the index of value. if not found return -1. func (l *List[T]) IndexOf(value T) int { index := -1 data := l.data for i, v := range data { if reflect.DeepEqual(v, value) { index = i break } } return index } // LastIndexOf returns the index of the last occurrence of the value in this list. // if not found return -1. func (l *List[T]) LastIndexOf(value T) int { index := -1 data := l.data for i := len(data) - 1; i >= 0; i-- { if reflect.DeepEqual(data[i], value) { index = i break } } return index } // IndexOfFunc returns the first index satisfying f(v) // if not found return -1. func (l *List[T]) IndexOfFunc(f func(T) bool) int { index := -1 data := l.data for i, v := range data { if f(v) { index = i break } } return index } // LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i]) // if not found return -1. func (l *List[T]) LastIndexOfFunc(f func(T) bool) int { index := -1 data := l.data for i := len(data) - 1; i >= 0; i-- { if f(data[i]) { index = i break } } return index } // Contain checks if the value in the list or not. func (l *List[T]) Contain(value T) bool { data := l.data for _, v := range data { if reflect.DeepEqual(v, value) { return true } } return false } // Push append value to the list data. func (l *List[T]) Push(value T) { l.data = append(l.data, value) } // InsertAtFirst insert value into list at first index. func (l *List[T]) InsertAtFirst(value T) { l.InsertAt(0, value) } // InsertAtLast insert value into list at last index. func (l *List[T]) InsertAtLast(value T) { l.InsertAt(len(l.data), value) } // InsertAt insert value into list at index. func (l *List[T]) InsertAt(index int, value T) { data := l.data size := len(data) if index < 0 || index > size { return } l.data = append(data[:index], append([]T{value}, data[index:]...)...) } // PopFirst delete the first value of list and return it. func (l *List[T]) PopFirst() (*T, bool) { if len(l.data) == 0 { return nil, false } v := l.data[0] l.DeleteAt(0) return &v, true } // PopLast delete the last value of list and return it. func (l *List[T]) PopLast() (*T, bool) { size := len(l.data) if size == 0 { return nil, false } v := l.data[size-1] l.DeleteAt(size - 1) return &v, true } // DeleteAt delete the value of list at index. func (l *List[T]) DeleteAt(index int) { data := l.data size := len(data) if index < 0 || index > size-1 { return } if index == size-1 { data = data[:index] } else { data = append(data[:index], data[index+1:]...) } l.data = data } // DeleteIf delete all satisfying f(data[i]), returns count of removed elements func (l *List[T]) DeleteIf(f func(T) bool) int { data := l.data size := len(data) var c int for index := 0; index < len(data); index++ { if !f(data[index]) { continue } if index == size-1 { data = data[:index] } else { data = append(data[:index], data[index+1:]...) index-- } c++ } if c > 0 { l.data = data } return c } // UpdateAt update value of list at index, index shoud between 0 and list size -1 func (l *List[T]) UpdateAt(index int, value T) { data := l.data size := len(data) if index < 0 || index >= size { return } l.data = append(data[:index], append([]T{value}, data[index+1:]...)...) } // Equal compare list to other list, use reflect.DeepEqual. func (l *List[T]) Equal(other *List[T]) bool { if len(l.data) != len(other.data) { return false } for i := 0; i < len(l.data); i++ { if !reflect.DeepEqual(l.data[i], other.data[i]) { return false } } return true } // IsEmpty check if the list is empty or not. func (l *List[T]) IsEmpty() bool { return len(l.data) == 0 } // Clear the data of list. func (l *List[T]) Clear() { l.data = make([]T, 0) } // Clone return a copy of list. func (l *List[T]) Clone() *List[T] { cl := NewList(make([]T, len(l.data))) copy(cl.data, l.data) return cl } // Merge two list, return new list, don't change original list. func (l *List[T]) Merge(other *List[T]) *List[T] { l1, l2 := len(l.data), len(other.data) ml := NewList(make([]T, l1+l2)) data := append([]T{}, append(l.data, other.data...)...) ml.data = data return ml } // Size return number of list data items. func (l *List[T]) Size() int { return len(l.data) } // Cap return cap of the inner data. func (l *List[T]) Cap() int { return cap(l.data) } // Swap the value of index i and j in list. func (l *List[T]) Swap(i, j int) { size := len(l.data) if i < 0 || i >= size || j < 0 || j >= size { return } l.data[i], l.data[j] = l.data[j], l.data[i] } // Reverse the item order of list. func (l *List[T]) Reverse() { for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 { l.data[i], l.data[j] = l.data[j], l.data[i] } } // Unique delete duplicate items in list. func (l *List[T]) Unique() { data := l.data size := len(data) uniqueData := make([]T, 0) for i := 0; i < size; i++ { value := data[i] skip := true for _, v := range uniqueData { if reflect.DeepEqual(value, v) { skip = false break } } if skip { uniqueData = append(uniqueData, value) } } l.data = uniqueData } // Union creates a new list contain all element in list l and other, delete duplicate element. func (l *List[T]) Union(other *List[T]) *List[T] { result := NewList([]T{}) result.data = append(result.data, l.data...) result.data = append(result.data, other.data...) result.Unique() return result } // Intersection creates a new list whose element both be contained in list l and other. func (l *List[T]) Intersection(other *List[T]) *List[T] { result := NewList(make([]T, 0)) for _, v := range l.data { if other.Contain(v) { result.data = append(result.data, v) } } return result } // Difference returns the difference between two collections. // return a list whose element in the original list, not in the given list. func (l *List[T]) Difference(other *List[T]) *List[T] { result := NewList(make([]T, 0)) intersectList := l.Intersection(other) for _, v := range l.data { if !intersectList.Contain(v) { result.data = append(result.data, v) } } return result } // SymmetricDifference oppoiste operation of intersection function. func (l *List[T]) SymmetricDifference(other *List[T]) *List[T] { result := NewList(make([]T, 0)) intersectList := l.Intersection(other) for _, v := range l.data { if !intersectList.Contain(v) { result.data = append(result.data, v) } } for _, v := range other.data { if !intersectList.Contain(v) { result.data = append(result.data, v) } } return result } // SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive. func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] { data := l.data[fromIndex:toIndex] subList := make([]T, len(data)) copy(subList, data) return NewList(subList) } // ForEach performs the given action for each element of the list. func (l *List[T]) ForEach(consumer func(T)) { for _, it := range l.data { consumer(it) } } // RetainAll retains only the elements in this list that are contained in the given list. func (l *List[T]) RetainAll(list *List[T]) bool { return l.batchRemove(list, true) } // DeleteAll removes from this list all of its elements that are contained in the given list. func (l *List[T]) DeleteAll(list *List[T]) bool { return l.batchRemove(list, false) } func (l *List[T]) batchRemove(list *List[T], complement bool) bool { var ( w = 0 data = l.data size = len(data) ) for i := 0; i < size; i++ { if list.Contain(data[i]) == complement { data[w] = data[i] w++ } } if w != size { l.data = data[:w] return true } return false } // Iterator returns an iterator over the elements in this list in proper sequence. func (l *List[T]) Iterator() iterator.Iterator[T] { return iterator.FromSlice(l.data) } // ListToMap convert a list to a map based on iteratee function. func ListToMap[T any, K comparable, V any](list *List[T], iteratee func(T) (K, V)) map[K]V { result := make(map[K]V, list.Size()) for _, item := range list.data { k, v := iteratee(item) result[k] = v } return result }