Skip to content

Commit

Permalink
Add flatten builtin (#684)
Browse files Browse the repository at this point in the history
  • Loading branch information
OlgaNovg authored Jul 15, 2024
1 parent 5e3d5a2 commit 5e660e7
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 0 deletions.
31 changes: 31 additions & 0 deletions builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,37 @@ var Builtins = []*Function{
return arrayType, nil
},
},
{
Name: "flatten",
Safe: func(args ...any) (any, uint, error) {
var size uint
if len(args) != 1 {
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(deref.Deref(args[0]))
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
return nil, size, fmt.Errorf("cannot flatten %s", v.Kind())
}
ret := flatten(v)
size = uint(len(ret))
return ret, size, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}

for _, arg := range args {
switch kind(deref.Type(arg)) {
case reflect.Interface, reflect.Slice, reflect.Array:
default:
return anyType, fmt.Errorf("cannot flatten %s", arg)
}
}

return arrayType, nil
},
},
{
Name: "sort",
Safe: func(args ...any) (any, uint, error) {
Expand Down
5 changes: 5 additions & 0 deletions builtin/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ func TestBuiltin(t *testing.T) {
{`reduce([], 5, 0)`, 0},
{`concat(ArrayOfString, ArrayOfInt)`, []any{"foo", "bar", "baz", 1, 2, 3}},
{`concat(PtrArrayWithNil, [nil])`, []any{42, nil}},
{`flatten([["a", "b"], [1, 2]])`, []any{"a", "b", 1, 2}},
{`flatten([["a", "b"], [1, 2, [3, 4]]])`, []any{"a", "b", 1, 2, 3, 4}},
{`flatten([["a", "b"], [1, 2, [3, [[[["c", "d"], "e"]]], 4]]])`, []any{"a", "b", 1, 2, 3, "c", "d", "e", 4}},
}

for _, test := range tests {
Expand Down Expand Up @@ -236,6 +239,8 @@ func TestBuiltin_errors(t *testing.T) {
{`now(nil)`, "invalid number of arguments (expected 0, got 1)"},
{`date(nil)`, "interface {} is nil, not string (1:1)"},
{`timezone(nil)`, "cannot use nil as argument (type string) to call timezone (1:10)"},
{`flatten([1, 2], [3, 4])`, "invalid number of arguments (expected 1, got 2)"},
{`flatten(1)`, "cannot flatten int"},
}
for _, test := range errorTests {
t.Run(test.input, func(t *testing.T) {
Expand Down
14 changes: 14 additions & 0 deletions builtin/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,17 @@ func median(args ...any) ([]float64, error) {
}
return values, nil
}

func flatten(arg reflect.Value) []any {
ret := []any{}
for i := 0; i < arg.Len(); i++ {
v := deref.Value(arg.Index(i))
if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
x := flatten(v)
ret = append(ret, x...)
} else {
ret = append(ret, v.Interface())
}
}
return ret
}
8 changes: 8 additions & 0 deletions docs/language-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,14 @@ Concatenates two or more arrays.
concat([1, 2], [3, 4]) == [1, 2, 3, 4]
```

### flatten(array) {#flatten}

Flattens given array into one-dimentional array.

```expr
flatten([1, 2, [3, 4]]) == [1, 2, 3, 4]
```

### join(array[, delimiter]) {#join}

Joins an array of strings into a single string with the given delimiter.
Expand Down

0 comments on commit 5e660e7

Please sign in to comment.