Skip to content

Commit

Permalink
feat(server): Create List as a generic pkg (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
akiyatomohiro authored Feb 29, 2024
1 parent 402668d commit 3cfdbe6
Show file tree
Hide file tree
Showing 2 changed files with 1,543 additions and 0 deletions.
343 changes: 343 additions & 0 deletions util/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ import (

type List[T comparable] []T

type Identifiable[ID comparable] interface {
ID() ID
}

type IDLister[ID comparable] interface {
LayerCount() int
Layers() []ID
}

type Converter[S any, T any] func(*S) *T

type ConverterValue[S any, T any] func(S) *T

func (l List[T]) Has(elements ...T) bool {
return Any(elements, func(e T) bool {
return slices.Contains(l, e)
Expand Down Expand Up @@ -128,3 +141,333 @@ func (l List[T]) Intersect(m []T) List[T] {
}
return lo.Intersect(m, l)
}

func Last[T any](list []*T) *T {
if len(list) == 0 {
return nil
}
return list[len(list)-1]
}

func ExtractIDs[ID comparable, T Identifiable[ID]](list []*T) []ID {
if len(list) == 0 {
return nil
}
ids := make([]ID, 0, len(list))
for _, item := range Deref[T](list, false) {
ids = append(ids, item.ID())
}
return ids
}

func Pick[ID comparable, T Identifiable[ID]](list []*T, idList IDLister[ID]) []*T {
if idList == nil || idList.LayerCount() == 0 {
return nil
}

layers := make([]*T, 0, idList.LayerCount())
for _, lid := range idList.Layers() {
if l := Find[ID, T](list, lid); l != nil {
layers = append(layers, l)
}
}
return layers
}

func Find[ID comparable, T Identifiable[ID]](list []*T, lid ID) *T {
for _, item := range list {
if item == nil {
continue
}
if (*item).ID() == lid {
return item
}
}
return nil
}

func Deref[T any](list []*T, skipNil bool) []T {
if !skipNil && list == nil {
return nil
}
res := make([]T, 0, len(list))
for _, item := range list {
if item == nil {
if !skipNil {
var zeroValue T
res = append(res, zeroValue)
}
continue
}
res = append(res, *item)
}
return res
}

func MapAdd[ID comparable, T Identifiable[ID]](m map[ID]*T, items ...*T) map[ID]*T {
if m == nil {
m = map[ID]*T{}
}
for _, item := range items {
if item == nil {
continue
}
m[(*item).ID()] = item
}
return m
}

func ListMap[ID comparable, T Identifiable[ID]](list []*T) map[ID]*T {
m := make(map[ID]*T, len(list))
MapAdd[ID, T](m, list...)
return m
}

func MapWithIDFunc[ID comparable, T any](list []*T, idFunc func(*T) ID, checkNil bool) map[ID]*T {
if checkNil && list == nil {
return nil
}
m := make(map[ID]*T, len(list))
for _, item := range list {
if item != nil {
id := idFunc(item)
m[id] = item
}
}
return m
}

func Merge[ID comparable, T Identifiable[ID]](m map[ID]*T, m2 map[ID]*T) map[ID]*T {
if m == nil {
return Clone[ID, T](m2)
}
m3 := Clone[ID, T](m)
if m2 == nil {
return m3
}

return MapAdd[ID, T](m3, MapList[ID, T](m2, false)...)
}

func ListMerge[T comparable](list []T, list2 []T, getClone func(T) T, duplicateSkip bool) []T {
result := make([]T, 0, len(list)+len(list2))

for _, item := range list {
result = append(result, getClone(item))
}

for _, item := range list2 {
if duplicateSkip {
if !Contains[T](result, item) {
result = append(result, getClone(item))
}
} else {
result = append(result, getClone(item))
}
}

return result
}

func MapList[ID comparable, T any](m map[ID]*T, skipNil bool) []*T {
if m == nil {
return nil
}
list := make([]*T, 0, len(m))
for _, l := range m {
if !skipNil || l != nil {
list = append(list, l)
}
}
return list
}

func Clone[ID comparable, T any](m map[ID]*T) map[ID]*T {
if m == nil {
return map[ID]*T{}
}
m2 := make(map[ID]*T, len(m))
for k, v := range m {
m2[k] = v
}
return m2
}

func ListClone[T any](list []T, getClone func(T) T) []T {
if list == nil {
return nil
}
list2 := make([]T, len(list))
for i, item := range list {
list2[i] = getClone(item)
}
return list2
}

func Remove[ID comparable, T Identifiable[ID]](list []*T, idsToRemove ...ID) []*T {
if list == nil {
return nil
}
if len(list) == 0 {
return []*T{}
}

result := make([]*T, 0, len(list))
for _, item := range list {
remove := false
for _, id := range idsToRemove {
if (*item).ID() == id {
remove = true
break
}
}
if !remove {
result = append(result, item)
}
}
return result
}

func AddUnique[ID comparable, T Identifiable[ID]](list []*T, newList []*T) []*T {
res := append([]*T{}, list...)

for _, l := range newList {
if l == nil {
continue
}
if Find[ID, T](res, (*l).ID()) != nil {
continue
}
res = append(res, l)
}

return res
}

func MapPick[ID comparable, T Identifiable[ID]](m map[ID]*T, idList IDLister[ID]) []*T {
if idList == nil || idList.LayerCount() == 0 {
return nil
}

layers := make([]*T, 0, idList.LayerCount())
for _, lid := range idList.Layers() {
if l := m[lid]; l != nil {
layers = append(layers, l)
}
}
return layers
}

func ExtractKeys[ID comparable, T any](m map[ID]*T) []ID {
keys := make([]ID, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}

func ToGenericList[S any, T any](list []*S, converter Converter[S, T]) []*T {
res := make([]*T, 0, len(list))
for _, l := range list {
if li := converter(l); li != nil {
res = append(res, li)
}
}
return res
}

func ToGenericListValue[S any, T any](list []S, converter ConverterValue[S, T]) []*T {
if len(list) == 0 {
return nil
}
res := make([]*T, 0, len(list))
for _, l := range list {
if li := converter(l); li != nil {
res = append(res, li)
}
}
return res
}

func ListHas[ID comparable, T any](list []*T, getId func(*T) ID, id ID) bool {
for _, item := range list {
if getId(item) == id {
return true
}
}
return false
}

func Get[ID comparable, T any](list []*T, getId func(*T) ID, id ID) *T {
for _, item := range list {
if getId(item) == id {
return item
}
}
return nil
}

func RemoveById[ID comparable, T any](list []*T, getId func(*T) ID, id ID) []*T {
for index, item := range list {
if getId(item) == id {
list = append(list[:index], list[index+1:]...)
return list
}
}
return list
}

func RemoveByIds[ID comparable, T any](list []*T, getId func(*T) ID, ids ...ID) []*T {
result := make([]*T, 0, len(list))
for _, item := range list {
itemID := getId(item)
if !Contains[ID](ids, itemID) {
result = append(result, item)
}
}
return result
}

func Contains[ID comparable](ids []ID, id ID) bool {
for _, i := range ids {
if i == id {
return true
}
}
return false
}

func Properties[ID comparable, T any](list []*T, getProperty func(*T) ID) []ID {
if list == nil {
return nil
}
ids := make([]ID, 0, len(list))
for _, item := range list {
if item != nil {
ids = append(ids, getProperty(item))
}
}
return ids
}

func ListFilter[ID comparable, T any](list []T, id ID, getId func(T) ID) []T {
if len(list) == 0 {
return nil
}
res := make([]T, 0, len(list))
for _, item := range list {
if getId(item) == id {
res = append(res, item)
}
}
return res
}

func IndexOf[ID comparable, T any](list []*T, getId func(*T) ID, id ID) int {
for index, item := range list {
if getId(item) == id {
return index
}
}
return -1
}
Loading

0 comments on commit 3cfdbe6

Please sign in to comment.