List

List is a collection with index. It implements IIndexableCollection.

Example

Create a List

package main

import (
	"github.com/KafkaWannaFly/generic-collections/list"
)

func main() {
	// You can create a new list from a slice
	integerList := list.From(1, 2, 3, 4, 5)

	// You also can chaining the Add method
	chainedList := list.New[int]()
	chainedList.Add(1).Add(2).Add(3).Add(4).Add(5)

	// You can add all elements from chainedList to integerList
	integerList.AddAll(chainedList)
}

Get and Set

package main

import (
	"fmt"
	"github.com/KafkaWannaFly/generic-collections/list"
)

type Warrior struct {
	Name      string
	BodyCount float64
}

func main() {
	eren := Warrior{"Eren", 1000}
	mikasa := Warrior{"Mikasa", 2000}
	armin := Warrior{"Armin", 3000}
	levi := Warrior{"Levi", 4000}
	hange := Warrior{"Hange", 5000}

	warriors := list.From(eren, mikasa, armin, levi, hange)

	// Loop through the warriors and print their names and body counts.
	warriors.ForEach(func(index int, warrior Warrior) {
		println(warrior.Name, warrior.BodyCount)
	})

	// Get the first warrior.
	firstItem := warriors.GetAt(0)
	// First warrior: {Eren 1000}
	fmt.Printf("First warrior: %v\n", firstItem)

	// Safe get operation.
	threeHundreds, ok := warriors.TryGetAt(300)
	// 300th warrior: { 0} false
	fmt.Printf("300th warrior: %v %t\n", threeHundreds, ok)
	
	// Set the 1st warrior to a new warrior.
	warriors.SetAt(0, Warrior{"Jean", 6000})
	// Safe set operation.
	warriors.TrySetAt(300, Warrior{"Connie", 7000}) // This will not change anything.
}

Map and Sum

package main

import (
	"fmt"
	"github.com/KafkaWannaFly/generic-collections/list"
)

type Warrior struct {
	Name      string
	BodyCount float64
}

func main() {
	eren := Warrior{"Eren", 1000}
	mikasa := Warrior{"Mikasa", 2000}
	armin := Warrior{"Armin", 3000}
	levi := Warrior{"Levi", 4000}
	hange := Warrior{"Hange", 5000}

	warriors := list.From(eren, mikasa, armin, levi, hange)

	// Due to Go limitation with generic. Data type is *list.List[any]
	anyBodies := warriors.Map(func(index int, warrior Warrior) any {
		return warrior.BodyCount
	})

	// To have better type safety, you can use the following approach
	// Data type is *list.List[float64]
	bodyCount := list.Map(warriors, func(index int, warrior Warrior) float64 {
		return warrior.BodyCount
	})

	// Use can use package functions to perform operations
	totalBodies := list.Reduce(bodyCount, func(accumulator float64, income float64) float64 {
		return accumulator + income
	}, 0)

	// Or you can use list methods
	// But have to cast the result to the desired type
	totalBodies = anyBodies.Reduce(func(acc any, income any) any {
		return acc.(float64) + income.(float64)
	}, 0.0).(float64)

	// Check for data type
	fmt.Println(list.IsList[Warrior](warriors)) // true

	fmt.Println(list.IsList[any](anyBodies))     // true
	fmt.Println(list.IsList[float64](anyBodies)) // false

	fmt.Println(list.IsList[float64](bodyCount)) // true

	// Total body count: 15000.000000
	fmt.Printf("Total body count: %f\n", totalBodies)
}

Grouping

package main

import (
	"fmt"
	"github.com/KafkaWannaFly/generic-collections/list"
)

type Warrior struct {
	Name      string
	BodyCount float64
}

func main() {
	eren := Warrior{"Eren", 1000}
	mikasa := Warrior{"Mikasa", 2000}
	armin := Warrior{"Armin", 3000}
	levi := Warrior{"Levi", 4000}
	hange := Warrior{"Hange", 5000}

	warriors := list.From(eren, mikasa, armin, levi, hange)

	// Group by BodyCount. Low tier warriors have BodyCount < 3000. High tier warriors have BodyCount >= 3000
	// We will have 2 groups: Low and High
	// Output will be a *hashmap.HashMap[any, *list.List[Warrior]]
	// 2 groups means 2 keys: Low and High
	// Once again, due to Go limitations, key type is any
	anyTier := warriors.GroupBy(func(warrior Warrior) any {
		if warrior.BodyCount < 3000 {
			return "Low"
		} else {
			return "High"
		}
	})

	// Use package function to have better type assertion
	// Data-type *hashmap.HashMap[string, *list.List[Warrior]]
	tier := list.GroupBy(warriors, func(warrior Warrior) string {
		if warrior.BodyCount < 3000 {
			return "Low"
		} else {
			return "High"
		}
	})

	// Low tier warriors: &{[{Eren 1000} {Mikasa 2000}] 2}
	fmt.Printf("Low tier warriors: %v\n", tier.Get("Low"))
	
	// High tier warriors: &{[{Armin 3000} {Levi 4000} {Hange 5000}] 3}
	fmt.Printf("High tier warriors: %v\n", anyTier.Get("High"))
}

Filtering

package main

import (
	"fmt"
	"github.com/KafkaWannaFly/generic-collections/list"
)

type Warrior struct {
	Name      string
	BodyCount float64
}

func main() {
	eren := Warrior{"Eren", 1000}
	mikasa := Warrior{"Mikasa", 2000}
	armin := Warrior{"Armin", 3000}
	levi := Warrior{"Levi", 4000}
	hange := Warrior{"Hange", 5000}

	warriors := list.From(eren, mikasa, armin, levi, hange)

	// Filter warriors with body count greater than 2000
	// Return a new list. Original list is not modified
	goodWarriors := warriors.Filter(func(warrior Warrior) bool {
		return warrior.BodyCount > 2000
	})

	// Good warriors: &{[{Armin 3000} {Levi 4000} {Hange 5000}] 3}
	fmt.Printf("Good warriors: %v\n", goodWarriors)
}

Slice a List

package main

import (
	"fmt"
	"github.com/KafkaWannaFly/generic-collections/list"
)

type Warrior struct {
	Name      string
	BodyCount float64
}

func main() {
	eren := Warrior{"Eren", 1000}
	mikasa := Warrior{"Mikasa", 2000}
	armin := Warrior{"Armin", 3000}
	levi := Warrior{"Levi", 4000}
	hange := Warrior{"Hange", 5000}

	warriors := list.From(eren, mikasa, armin, levi, hange)

	// Cut the list to the first two elements.
	teamEren := warriors.Slice(0, 2)
	// Small team: &{[{Eren 1000} {Mikasa 2000}] 2}
	fmt.Printf("Small team: %v\n", teamEren)

	// Cut the list to the last two elements.
	teamLevi := warriors.Slice(3, 2)
	// Levi's team: &{[{Levi 4000} {Hange 5000}] 2}
	fmt.Printf("Levi's team: %v\n", teamLevi)

	// If length is surpassed the end, it will loop back to the beginning.
	merryGoRound := warriors.Slice(3, 5)
	// &{[{Levi 4000} {Hange 5000} {Eren 1000} {Mikasa 2000} {Armin 3000}] 5}
	fmt.Println(merryGoRound)
}

Last updated