Skip to content

Commit e28d9aa

Browse files
adiabaticbep
authored andcommitted
tpl: Add uniq function
1 parent 46b4607 commit e28d9aa

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

‎docs/content/templates/functions.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,15 @@ e.g.
373373
{{ .Content }}
374374
{{ end }}
375375

376+
377+
### uniq
378+
379+
Takes in a slice or array and returns a slice with subsequent duplicate elements removed.
380+
381+
{{ uniq (slice 1 2 3 2) }}
382+
{{ slice 1 2 3 2 | uniq }}
383+
<!-- both return [1 2 3] -->
384+
376385
## Files
377386

378387
### readDir

‎tpl/collections/collections.go‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,3 +587,41 @@ func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
587587
return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
588588
}
589589
}
590+
591+
// Uniq takes in a slice or array and returns a slice with subsequent
592+
// duplicate elements removed.
593+
func (ns *Namespace) Uniq(l interface{}) (interface{}, error) {
594+
if l == nil {
595+
return make([]interface{}, 0), nil
596+
}
597+
598+
lv := reflect.ValueOf(l)
599+
lv, isNil := indirect(lv)
600+
if isNil {
601+
return nil, errors.New("invalid nil argument to Uniq")
602+
}
603+
604+
var ret reflect.Value
605+
606+
switch lv.Kind() {
607+
case reflect.Slice:
608+
ret = reflect.MakeSlice(lv.Type(), 0, 0)
609+
case reflect.Array:
610+
ret = reflect.MakeSlice(reflect.SliceOf(lv.Type().Elem()), 0, 0)
611+
default:
612+
return nil, errors.New("Can't use Uniq on " + reflect.ValueOf(lv).Type().String())
613+
}
614+
615+
for i := 0; i != lv.Len(); i++ {
616+
lvv := lv.Index(i)
617+
lvv, isNil := indirect(lvv)
618+
if isNil {
619+
continue
620+
}
621+
622+
if !ns.In(ret.Interface(), lvv.Interface()) {
623+
ret = reflect.Append(ret, lvv)
624+
}
625+
}
626+
return ret.Interface(), nil
627+
}

‎tpl/collections/collections_test.go‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,42 @@ func TestUnion(t *testing.T) {
603603
}
604604
}
605605

606+
func TestUniq(t *testing.T) {
607+
t.Parallel()
608+
609+
ns := New(&deps.Deps{})
610+
for i, test := range []struct {
611+
l interface{}
612+
expect interface{}
613+
isErr bool
614+
}{
615+
{[]string{"a", "b", "c"}, []string{"a", "b", "c"}, false},
616+
{[]string{"a", "b", "c", "c"}, []string{"a", "b", "c"}, false},
617+
{[]string{"a", "b", "b", "c"}, []string{"a", "b", "c"}, false},
618+
{[]string{"a", "b", "c", "b"}, []string{"a", "b", "c"}, false},
619+
{[]int{1, 2, 3}, []int{1, 2, 3}, false},
620+
{[]int{1, 2, 3, 3}, []int{1, 2, 3}, false},
621+
{[]int{1, 2, 2, 3}, []int{1, 2, 3}, false},
622+
{[]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
623+
{[4]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
624+
{nil, make([]interface{}, 0), false},
625+
// should-errors
626+
{1, 1, true},
627+
{"foo", "fo", true},
628+
} {
629+
errMsg := fmt.Sprintf("[%d] %v", i, test)
630+
631+
result, err := ns.Uniq(test.l)
632+
if test.isErr {
633+
assert.Error(t, err, errMsg)
634+
continue
635+
}
636+
637+
assert.NoError(t, err, errMsg)
638+
assert.Equal(t, test.expect, result, errMsg)
639+
}
640+
}
641+
606642
func (x *TstX) TstRp() string {
607643
return "r" + x.A
608644
}

‎tpl/collections/init.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ func init() {
137137
{`{{ seq 3 }}`, `[1 2 3]`},
138138
},
139139
)
140+
ns.AddMethodMapping(ctx.Uniq,
141+
[]string{"uniq"},
142+
[][2]string{
143+
{`{{ slice 1 2 3 2 | uniq }}`, `[1 2 3]`},
144+
},
145+
)
140146

141147
return ns
142148

0 commit comments

Comments
 (0)