Skip to content

Commit

Permalink
cleanup usage of orderedmap
Browse files Browse the repository at this point in the history
add tests
add groupby
add groupbyordered
  • Loading branch information
maddalax committed Oct 29, 2024
1 parent d44cd0b commit cb012a4
Show file tree
Hide file tree
Showing 12 changed files with 230 additions and 211 deletions.
82 changes: 0 additions & 82 deletions cli/htmgo/tasks/astgen/map.go

This file was deleted.

13 changes: 0 additions & 13 deletions cli/htmgo/tasks/astgen/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,3 @@ import (
func PanicF(format string, args ...interface{}) {
panic(fmt.Sprintf(format, args...))
}

func Unique[T any](slice []T, key func(item T) string) []T {
var result []T
seen := make(map[string]bool)
for _, v := range slice {
k := key(v)
if _, ok := seen[k]; !ok {
seen[k] = true
result = append(result, v)
}
}
return result
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package datastructures
package orderedmap

// OrderedMap is a generic data structure that maintains the order of keys.
type OrderedMap[K comparable, V any] struct {
type Entry[K comparable, V any] struct {
Key K
Value V
}

// Map is a generic data structure that maintains the order of keys.
type Map[K comparable, V any] struct {
keys []K
values map[K]V
}

type Entry[K comparable, V any] struct {
Key K
Value V
func (om *Map[K, V]) Each(cb func(key K, value V)) {
for _, key := range om.keys {
cb(key, om.values[key])
}
}

// Entries returns the key-value pairs in the order they were added.
func (om *OrderedMap[K, V]) Entries() []Entry[K, V] {
func (om *Map[K, V]) Entries() []Entry[K, V] {
entries := make([]Entry[K, V], len(om.keys))
for i, key := range om.keys {
entries[i] = Entry[K, V]{
Expand All @@ -23,16 +29,16 @@ func (om *OrderedMap[K, V]) Entries() []Entry[K, V] {
return entries
}

// NewOrderedMap creates a new OrderedMap.
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
return &OrderedMap[K, V]{
// New creates a new Map.
func New[K comparable, V any]() *Map[K, V] {
return &Map[K, V]{
keys: []K{},
values: make(map[K]V),
}
}

// Set adds or updates a key-value pair in the OrderedMap.
func (om *OrderedMap[K, V]) Set(key K, value V) {
// Set adds or updates a key-value pair in the Map.
func (om *Map[K, V]) Set(key K, value V) {
// Check if the key already exists
if _, exists := om.values[key]; !exists {
om.keys = append(om.keys, key) // Append key to the keys slice if it's a new key
Expand All @@ -41,18 +47,18 @@ func (om *OrderedMap[K, V]) Set(key K, value V) {
}

// Get retrieves a value by key.
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
func (om *Map[K, V]) Get(key K) (V, bool) {
value, exists := om.values[key]
return value, exists
}

// Keys returns the keys in the order they were added.
func (om *OrderedMap[K, V]) Keys() []K {
func (om *Map[K, V]) Keys() []K {
return om.keys
}

// Values returns the values in the order of their keys.
func (om *OrderedMap[K, V]) Values() []V {
func (om *Map[K, V]) Values() []V {
values := make([]V, len(om.keys))
for i, key := range om.keys {
values[i] = om.values[key]
Expand All @@ -61,8 +67,8 @@ func (om *OrderedMap[K, V]) Values() []V {
return values
}

// Delete removes a key-value pair from the OrderedMap.
func (om *OrderedMap[K, V]) Delete(key K) {
// Delete removes a key-value pair from the Map.
func (om *Map[K, V]) Delete(key K) {
if _, exists := om.values[key]; exists {
// Remove the key from the map
delete(om.values, key)
Expand Down
33 changes: 33 additions & 0 deletions framework/datastructure/orderedmap/orderedmap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package orderedmap

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestOrderedMap(t *testing.T) {
t.Parallel()
om := New[string, int]()

alphabet := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
for index, letter := range alphabet {
om.Set(letter, index)
}

assert.Equal(t, alphabet, om.Keys())

c, ok := om.Get("c")
assert.True(t, ok)
assert.Equal(t, 2, c)

for i, entry := range om.Entries() {
if i == 5 {
assert.Equal(t, "f", entry.Key)
}
}

om.Delete("c")
value, ok := om.Get("c")
assert.False(t, ok)
assert.Equal(t, 0, value)
}
33 changes: 33 additions & 0 deletions framework/h/array.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package h

import (
"github.com/maddalax/htmgo/framework/datastructure/orderedmap"
)

// Unique returns a new slice with only unique items.
func Unique[T any](slice []T, key func(item T) string) []T {
var result []T
Expand All @@ -14,6 +18,7 @@ func Unique[T any](slice []T, key func(item T) string) []T {
return result
}

// Find returns the first item in the slice that matches the predicate.
func Find[T any](slice []T, predicate func(item *T) bool) *T {
for _, v := range slice {
if predicate(&v) {
Expand All @@ -23,6 +28,34 @@ func Find[T any](slice []T, predicate func(item *T) bool) *T {
return nil
}

// GroupBy groups the items in the slice by the key returned by the key function.
func GroupBy[T any, K comparable](slice []T, key func(item T) K) map[K][]T {
grouped := make(map[K][]T)
for _, item := range slice {
k := key(item)
items, ok := grouped[k]
if !ok {
items = []T{}
}
grouped[k] = append(items, item)
}
return grouped
}

// GroupByOrdered groups the items in the slice by the key returned by the key function, and returns an Map.
func GroupByOrdered[T any, K comparable](slice []T, key func(item T) K) *orderedmap.Map[K, []T] {
grouped := orderedmap.New[K, []T]()
for _, item := range slice {
k := key(item)
items, ok := grouped.Get(k)
if !ok {
items = []T{}
}
grouped.Set(k, append(items, item))
}
return grouped
}

// Filter returns a new slice with only items that match the predicate.
func Filter[T any](slice []T, predicate func(item T) bool) []T {
var result []T
Expand Down
102 changes: 102 additions & 0 deletions framework/h/array_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package h

import (
"github.com/stretchr/testify/assert"
"strings"
"testing"
)

func TestUnique(t *testing.T) {
t.Parallel()
slice := []string{"a", "b", "b", "c", "d", "d", "x"}
unique := Unique(slice, func(item string) string {
return item
})
assert.Equal(t, []string{"a", "b", "c", "d", "x"}, unique)
}

func TestFilter(t *testing.T) {
t.Parallel()
slice := []string{"a", "b", "b", "c", "d", "d", "x"}
filtered := Filter(slice, func(item string) bool {
return item == "b"
})
assert.Equal(t, []string{"b", "b"}, filtered)
}

func TestMap(t *testing.T) {
t.Parallel()
slice := []string{"a", "b", "c"}
mapped := Map(slice, func(item string) string {
return strings.ToUpper(item)
})
assert.Equal(t, []string{"A", "B", "C"}, mapped)
}

func TestGroupBy(t *testing.T) {
t.Parallel()

type Item struct {
Name string
Job string
}

items := []Item{
{Name: "Alice", Job: "Developer"},
{Name: "Bob", Job: "Designer"},
{Name: "Charlie", Job: "Developer"},
{Name: "David", Job: "Designer"},
{Name: "Eve", Job: "Developer"},
{Name: "Frank", Job: "Product Manager"},
}

grouped := GroupBy(items, func(item Item) string {
return item.Job
})

assert.Equal(t, 3, len(grouped))
assert.Equal(t, 3, len(grouped["Developer"]))
assert.Equal(t, 2, len(grouped["Designer"]))
assert.Equal(t, 1, len(grouped["Product Manager"]))
}

func TestGroupByOrdered(t *testing.T) {
t.Parallel()

type Item struct {
Name string
Job string
}

items := []Item{
{Name: "Alice", Job: "Developer"},
{Name: "Bob", Job: "Designer"},
{Name: "Charlie", Job: "Developer"},
{Name: "David", Job: "Designer"},
{Name: "Eve", Job: "Developer"},
{Name: "Frank", Job: "Product Manager"},
}

grouped := GroupByOrdered(items, func(item Item) string {
return item.Job
})

keys := []string{"Developer", "Designer", "Product Manager"}
assert.Equal(t, keys, grouped.Keys())

devs, ok := grouped.Get("Developer")
assert.True(t, ok)
assert.Equal(t, 3, len(devs))
assert.Equal(t, "Alice", devs[0].Name)
assert.Equal(t, "Charlie", devs[1].Name)
assert.Equal(t, "Eve", devs[2].Name)
}

func TestFind(t *testing.T) {
t.Parallel()
slice := []string{"a", "b", "c"}
found := Find(slice, func(item *string) bool {
return *item == "b"
})
assert.Equal(t, "b", *found)
}
Loading

0 comments on commit cb012a4

Please sign in to comment.