Skip to content

Commit

Permalink
tpl: Add uniq function
Browse files Browse the repository at this point in the history
  • Loading branch information
adiabatic authored and bep committed Jun 3, 2017
1 parent 46b4607 commit e28d9aa
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
9 changes: 9 additions & 0 deletions docs/content/templates/functions.md
Expand Up @@ -373,6 +373,15 @@ e.g.
{{ .Content }}
{{ end }}


### uniq

Takes in a slice or array and returns a slice with subsequent duplicate elements removed.

{{ uniq (slice 1 2 3 2) }}
{{ slice 1 2 3 2 | uniq }}
<!-- both return [1 2 3] -->

## Files

### readDir
Expand Down
38 changes: 38 additions & 0 deletions tpl/collections/collections.go
Expand Up @@ -587,3 +587,41 @@ func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
}
}

// Uniq takes in a slice or array and returns a slice with subsequent
// duplicate elements removed.
func (ns *Namespace) Uniq(l interface{}) (interface{}, error) {
if l == nil {
return make([]interface{}, 0), nil
}

lv := reflect.ValueOf(l)
lv, isNil := indirect(lv)
if isNil {
return nil, errors.New("invalid nil argument to Uniq")
}

var ret reflect.Value

switch lv.Kind() {
case reflect.Slice:
ret = reflect.MakeSlice(lv.Type(), 0, 0)
case reflect.Array:
ret = reflect.MakeSlice(reflect.SliceOf(lv.Type().Elem()), 0, 0)
default:
return nil, errors.New("Can't use Uniq on " + reflect.ValueOf(lv).Type().String())
}

for i := 0; i != lv.Len(); i++ {
lvv := lv.Index(i)
lvv, isNil := indirect(lvv)
if isNil {
continue
}

if !ns.In(ret.Interface(), lvv.Interface()) {
ret = reflect.Append(ret, lvv)
}
}
return ret.Interface(), nil
}
36 changes: 36 additions & 0 deletions tpl/collections/collections_test.go
Expand Up @@ -603,6 +603,42 @@ func TestUnion(t *testing.T) {
}
}

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

ns := New(&deps.Deps{})
for i, test := range []struct {
l interface{}
expect interface{}
isErr bool
}{
{[]string{"a", "b", "c"}, []string{"a", "b", "c"}, false},
{[]string{"a", "b", "c", "c"}, []string{"a", "b", "c"}, false},
{[]string{"a", "b", "b", "c"}, []string{"a", "b", "c"}, false},
{[]string{"a", "b", "c", "b"}, []string{"a", "b", "c"}, false},
{[]int{1, 2, 3}, []int{1, 2, 3}, false},
{[]int{1, 2, 3, 3}, []int{1, 2, 3}, false},
{[]int{1, 2, 2, 3}, []int{1, 2, 3}, false},
{[]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
{[4]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
{nil, make([]interface{}, 0), false},
// should-errors
{1, 1, true},
{"foo", "fo", true},
} {
errMsg := fmt.Sprintf("[%d] %v", i, test)

result, err := ns.Uniq(test.l)
if test.isErr {
assert.Error(t, err, errMsg)
continue
}

assert.NoError(t, err, errMsg)
assert.Equal(t, test.expect, result, errMsg)
}
}

func (x *TstX) TstRp() string {
return "r" + x.A
}
Expand Down
6 changes: 6 additions & 0 deletions tpl/collections/init.go
Expand Up @@ -137,6 +137,12 @@ func init() {
{`{{ seq 3 }}`, `[1 2 3]`},
},
)
ns.AddMethodMapping(ctx.Uniq,
[]string{"uniq"},
[][2]string{
{`{{ slice 1 2 3 2 | uniq }}`, `[1 2 3]`},
},
)

return ns

Expand Down

0 comments on commit e28d9aa

Please sign in to comment.