github.com/m4gshm/gollections@v0.0.10/README.md (about)

     1  # Gollections
     2  
     3  This is a set of utilities aimed at reducing boilerplate code when using
     4  [slices](./slice/api.go), [maps](./map_/api.go) and extending
     5  functionality by new collection implementations such as [ordered
     6  map](./collection/collection/mutable/omap/api.go) or
     7  [set](./collection/collection/mutable/oset/api.go).
     8  
     9  Supports Go version 1.20.
    10  
    11  For example, you want to group some
    12  [users](./internal/examples/boilerplate/user_type.go) by their role
    13  names converted to lowercase:
    14  
    15  ``` go
    16  var users = []User{
    17      {name: "Bob", age: 26, roles: []Role{{"Admin"}, {"manager"}}},
    18      {name: "Alice", age: 35, roles: []Role{{"Manager"}}},
    19      {name: "Tom", age: 18},
    20  }
    21  ```
    22  
    23  You can make clear code, extensive, but without dependencies:
    24  
    25  ``` go
    26  var namesByRole = map[string][]string{}
    27  add := func(role string, u User) {
    28      namesByRole[role] = append(namesByRole[role], u.Name())
    29  }
    30  for _, u := range users {
    31      roles := u.Roles()
    32      if len(roles) == 0 {
    33          add("", u)
    34      } else {
    35          for _, r := range roles {
    36              add(strings.ToLower(r.Name()), u)
    37          }
    38      }
    39  }
    40  
    41  assert.Equal(t, namesByRole[""], []string{"Tom"})
    42  assert.Equal(t, namesByRole["manager"], []string{"Bob", "Alice"})
    43  assert.Equal(t, namesByRole["admin"], []string{"Bob"})
    44  ```
    45  
    46  Or you can write more compact code using the collections API, like so:
    47  
    48  ``` go
    49  var namesByRole = group.ByMultipleKeys(users, func(u User) []string {
    50      return convert.AndConvert(u.Roles(), Role.Name, strings.ToLower)
    51  }, User.Name)
    52  
    53  assert.Equal(t, namesByRole[""], []string{"Tom"})
    54  assert.Equal(t, namesByRole["manager"], []string{"Bob", "Alice"})
    55  assert.Equal(t, namesByRole["admin"], []string{"Bob"})
    56  ```
    57  
    58  ## Installation
    59  
    60  ``` console
    61  go get -u github.com/m4gshm/gollections
    62  ```
    63  
    64  or
    65  
    66  ``` console
    67  go get -u github.com/m4gshm/gollections@HEAD
    68  ```
    69  
    70  ## Main packages
    71  
    72  All packages consists of functions placed in the package and subpackages
    73  aimed to make short aliases of that functions. For example the function
    74  [slice.SortByOrdered](./slice/api.go#L459) has aliases
    75  [sort.By](./slice/sort/api.go#L12) and
    76  [sort.Of](./slice/sort/api.go#L23).
    77  
    78  ### [slice](./slice/api.go) and [map\_](./map_/api.go)
    79  
    80  Contains utility functions of [converting](./slice/api.go#L156),
    81  [filtering](./slice/api.go#L379) (searching),
    82  [reducing](./slice/api.go#L464), [cloning](./map_/api.go#L90) elements
    83  of embedded slices and maps. The functions compute result in-place. For
    84  delayed computations see
    85  [loops](#loop-kvloop-and-breakable-versions-breakloop-breakkvloop) or
    86  [collection functions](#collection-functions).
    87  
    88  ``` go
    89  even := func(i int) bool { return i%2 == 0 }
    90  result := slice.Reduce(
    91      slice.Convert(
    92          slice.Filter(slice.Of(1, 2, 3, 4), even),
    93          strconv.Itoa,
    94      ),
    95      op.Sum[string],
    96  )
    97  
    98  assert.Equal(t, "24", result)
    99  ```
   100  
   101  More examples
   102  [here](./internal/examples/sliceexamples/slice_examples_test.go) and
   103  [here](./internal/examples/mapexamples/map_examples_test.go).
   104  
   105  ### [mutable](./collection/mutable/api.go) and [immutable](./collection/immutable/api.go) collections
   106  
   107  Provides implelentations of [Vector](./collection/iface.go#L25),
   108  [Set](./collection/iface.go#L35) and [Map](./collection/iface.go#L41).
   109  
   110  Mutables support content appending, updating and deleting (the ordered
   111  map implementation is not supported delete operations).  
   112  Immutables are read-only datasets.
   113  
   114  Detailed description of implementations [below](#mutable-collections).
   115  
   116  ### [predicate](./predicate/api.go) and breakable [break/predicate](./predicate/api.go)
   117  
   118  Provides predicate builder api that used for filtering collection
   119  elements.
   120  
   121  ``` go
   122  bob, _ := slice.First(users, where.Eq(User.Name, "Bob"))
   123  
   124  assert.Equal(t, "Bob", bob.Name())
   125  ```
   126  
   127  ### [loop](./loop/api.go), [kv/loop](./kv/loop/api.go) and breakable versions [break/loop](./break/loop/api.go), [break/kv/loop](./break/kv/loop/api.go)
   128  
   129  Low level iteration api based on `next` function.
   130  
   131  ``` go
   132  type (
   133      next[T any]      func() (element T, ok bool)
   134      kvNext[K, V any] func() (key K, value V, ok bool)
   135  )
   136  ```
   137  
   138  The function retrieves a next element from a dataset and returns
   139  `ok==true` if successful.  
   140  The API in most cases is similar to the [slice](./slice/api.go) API but
   141  with delayed computation which means that the methods don’t compute a
   142  result but only return a loop provider. The loop provider is type with a
   143  `Next` method that returns a next processed element.
   144  
   145  ``` go
   146  even := func(i int) bool { return i%2 == 0 }
   147  loopStream := loop.Convert(loop.Filter(loop.Of(1, 2, 3, 4), even).Next, strconv.Itoa)
   148  
   149  assert.Equal(t, []string{"2", "4"}, loop.Slice(loopStream.Next))
   150  ```
   151  
   152  Breakable loops additionaly have error returned value.
   153  
   154  ``` go
   155  type (
   156      next[T any]      func() (element T, ok bool, err error)
   157      kvNext[K, V any] func() (key K, value V, ok bool, err error)
   158  )
   159  ```
   160  
   161  It is used for computations where an error may occur.
   162  
   163  ``` go
   164  iter := loop.Conv(loop.Of("1", "2", "3", "ddd4", "5"), strconv.Atoi)
   165  result, err := loop.Slice(iter.Next)
   166  
   167  assert.Equal(t, []int{1, 2, 3}, result)
   168  assert.ErrorContains(t, err, "invalid syntax")
   169  ```
   170  
   171  ## Expressions: [use](./expr/use/api.go), [get](./expr/get/api.go), [first](./expr/first/api.go), [last](./expr/last/api.go)
   172  
   173  Aimed to evaluate a value using conditions. May cause to make code
   174  shorter by not in all cases.  
   175  As example:
   176  
   177  ``` go
   178  user := User{name: "Bob", surname: "Smith"}
   179  
   180  fullName := use.If(len(user.surname) == 0, user.name).If(len(user.name) == 0, user.surname).
   181      ElseGet(func() string { return user.name + " " + user.surname })
   182  
   183  assert.Equal(t, "Bob Smith", fullName)
   184  ```
   185  
   186  instead of:
   187  
   188  ``` go
   189  fullName := ""
   190  if len(user.surname) == 0 {
   191      fullName = user.name
   192  } else if len(user.name) == 0 {
   193      fullName = user.surname
   194  } else {
   195      fullName = user.name + " " + user.surname
   196  }
   197  
   198  assert.Equal(t, "Bob Smith", fullName)
   199  ```
   200  
   201  ## Mutable collections
   202  
   203  Supports write operations (append, delete, replace).
   204  
   205  - [Vector](./collection/mutable/vector/api.go) - the simplest based on
   206    built-in slice collection.
   207  
   208  ``` go
   209  _ *mutable.Vector[int]   = vector.Of(1, 2, 3)
   210  _ collection.Vector[int] = &mutable.Vector[int]{}
   211  ```
   212  
   213  - [Set](./collection/mutable/set/api.go) - collection of unique items,
   214    prevents duplicates.
   215  
   216  ``` go
   217  _ *mutable.Set[int]   = set.Of(1, 2, 3)
   218  _ collection.Set[int] = &mutable.Set[int]{}
   219  ```
   220  
   221  - [Map](./collection/mutable/map_/api.go) - built-in map wrapper that
   222    supports [stream functions](#stream-functions).
   223  
   224  ``` go
   225  _ *mutable.Map[int, string]   = map_.Of(k.V(1, "1"), k.V(2, "2"), k.V(3, "3"))
   226  _ collection.Map[int, string] = mutable.NewMapOf(map[int]string{1: "2", 2: "2", 3: "3"})
   227  ```
   228  
   229  - [OrderedSet](./collection/mutable/oset/api.go) - collection of unique
   230    items, prevents duplicates, provides iteration in order of addition.
   231  
   232  ``` go
   233  _ *ordered.Set[int]   = set.Of(1, 2, 3)
   234  _ collection.Set[int] = &ordered.Set[int]{}
   235  ```
   236  
   237  - [OrderedMap](./collection/mutable/omap/api.go) - same as the Map, but
   238    supports iteration in the order in which elements are added.
   239  
   240  ``` go
   241  _ *ordered.Map[int, string]   = map_.Of(k.V(1, "1"), k.V(2, "2"), k.V(3, "3"))
   242  _ collection.Map[int, string] = ordered.NewMapOf(
   243      /*order  */ []int{3, 1, 2},
   244      /*uniques*/ map[int]string{1: "2", 2: "2", 3: "3"},
   245  )
   246  ```
   247  
   248  ### Immutable containers
   249  
   250  The same underlying interfaces but for read-only use cases.
   251  
   252  ## Collection functions
   253  
   254  There are three groups of operations:
   255  
   256  - Immediate - retrieves the result in place
   257    ([Sort](./collection/mutable/vector.go#L322),
   258    [Reduce](./collection/immutable/vector.go#L154),
   259    [Track](./collection/immutable/vector.go#L111),
   260    [TrackEach](./collection/mutable/ordered/map.go#L182),
   261    [For](./collection/immutable/vector.go#L122),
   262    [ForEach](./collection/immutable/ordered/map.go#L175))
   263  
   264  - Intermediate - only defines a computation
   265    ([Convert](./collection/api.go#L17),
   266    [Filter](./collection/immutable/ordered/set.go#L124),
   267    [Flatt](./collection/api.go#L36), [Group](./collection/api.go#L69)).
   268  
   269  - Final - applies intermediates and retrieves a result
   270    ([First](./collection/api.go#L75),
   271    [Slice](./collection/immutable/ordered/set.go#L94),
   272    [Reduce](./collection/immutable/ordered/set.go#L146))
   273  
   274  Intermediates should wrap one by one to make a lazy computation chain
   275  that can be applied to the latest final operation.
   276  
   277  ``` go
   278  var groupedByLength = group.Of(set.Of(
   279      "seventh", "seventh", //duplicate
   280      "first", "second", "third", "fourth",
   281      "fifth", "sixth", "eighth",
   282      "ninth", "tenth", "one", "two", "three", "1",
   283      "second", //duplicate
   284  ), func(v string) int { return len(v) },
   285  ).FilterKey(
   286      more.Than(3),
   287  ).ConvertValue(
   288      func(v string) string { return v + "_" },
   289  ).Map()
   290  
   291  assert.Equal(t, map[int][]string{
   292      5: {"first_", "third_", "fifth_", "sixth_", "ninth_", "tenth_", "three_"},
   293      6: {"second_", "fourth_", "eighth_"},
   294      7: {"seventh_"},
   295  }, groupedByLength)
   296  ```