pkg/list: adding flatten function as a builtin
this commit adds a new builtin to the list package for generating a
flat list from a nested lists by expanding nested lists in place.
for instance
list.Flatten([1, [[2, 3], []], [4]])
results in
[1, 2, 3, 4]
Change-Id: Ia462f7f2db504fd49601a3c77c0fae9387c038c4
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3460
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/builtin_test.go b/cue/builtin_test.go
index 34979a8..0610c90 100644
--- a/cue/builtin_test.go
+++ b/cue/builtin_test.go
@@ -156,6 +156,12 @@
test("list", `list.Drop([1, 2, 3, 4], -1)`),
`_|_(error in call to list.Drop: negative index)`,
}, {
+ test("list", `list.Flatten([1, [[2, 3], []], [4]])`),
+ `[1,2,3,4]`,
+ }, {
+ test("list", `list.Flatten("foo")`),
+ `_|_(error in call to list.Flatten: cannot use value "foo" (type string) as list)`,
+ }, {
test("list", `list.Max([1, 2, 3, 4])`),
`4`,
}, {
diff --git a/cue/builtins.go b/cue/builtins.go
index a055e9a..037fa33 100644
--- a/cue/builtins.go
+++ b/cue/builtins.go
@@ -681,6 +681,37 @@
}()
},
}, {
+ Name: "Flatten",
+ Params: []kind{topKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ xs := c.value(0)
+ c.ret, c.err = func() (interface{}, error) {
+ var flatten func(Value) ([]Value, error)
+ flatten = func(xs Value) ([]Value, error) {
+ var res []Value
+ iter, err := xs.List()
+ if err != nil {
+ return nil, err
+ }
+ for iter.Next() {
+ val := iter.Value()
+ if val.Kind() == ListKind {
+ vals, err := flatten(val)
+ if err != nil {
+ return nil, err
+ }
+ res = append(res, vals...)
+ } else {
+ res = append(res, val)
+ }
+ }
+ return res, nil
+ }
+ return flatten(xs)
+ }()
+ },
+ }, {
Name: "Take",
Params: []kind{listKind, intKind},
Result: listKind,
diff --git a/pkg/list/list.go b/pkg/list/list.go
index 9249f3f..fa8c869 100644
--- a/pkg/list/list.go
+++ b/pkg/list/list.go
@@ -45,6 +45,42 @@
return x[n:], nil
}
+// Flatten reports a flattend sequence of the list x by expanding any elements
+// that are lists.
+//
+// For instance:
+//
+// Flatten([1, [[2, 3], []], [4]])
+//
+// results in
+//
+// [1, 2, 3, 4]
+//
+func Flatten(xs cue.Value) ([]cue.Value, error) {
+ var flatten func(cue.Value) ([]cue.Value, error)
+ flatten = func(xs cue.Value) ([]cue.Value, error) {
+ var res []cue.Value
+ iter, err := xs.List()
+ if err != nil {
+ return nil, err
+ }
+ for iter.Next() {
+ val := iter.Value()
+ if val.Kind() == cue.ListKind {
+ vals, err := flatten(val)
+ if err != nil {
+ return nil, err
+ }
+ res = append(res, vals...)
+ } else {
+ res = append(res, val)
+ }
+ }
+ return res, nil
+ }
+ return flatten(xs)
+}
+
// Take reports the prefix of length n of list x, or x itself if n > len(x).
//
// For instance: