Skip to content

Instantly share code, notes, and snippets.

@thisiscetin
Last active January 27, 2017 15:15
Show Gist options
  • Save thisiscetin/9ef44736479b1399e99981be4ac3d857 to your computer and use it in GitHub Desktop.
Save thisiscetin/9ef44736479b1399e99981be4ac3d857 to your computer and use it in GitHub Desktop.
int slice at infinite dimension
package nested
import (
"errors"
"fmt"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
)
// NestedBlock, primary data structure for adding dimension to our slices
type NestedBlock struct {
depth int
content int
}
// NestedSlice holds nested blocks, which can have infinitely many dimensions
// through declared depth
type NestedSlice []*NestedBlock
// ParseNestedSlice parses nested slice to predefined type NestedSlice
// which is responsible of holding our custom data structure NestedBlocks
func ParseNestedSlice(sliceStr string) (NestedSlice, error) {
var ns NestedSlice
ns = make([]*NestedBlock, 0, 1)
var (
depth int
numberStart int
)
for k, r := range sliceStr {
switch r {
case '[':
depth++
numberStart = k + 1
case ']':
depth--
case ',':
numberStart = k + 1
continue
case ' ':
return nil, errors.New("do not use blank spaces on nested slice declaration")
default:
if k+1 == len(sliceStr) {
break
}
if sliceStr[k+1] == ']' || sliceStr[k+1] == ',' {
n, err := strconv.Atoi(sliceStr[numberStart : k+1])
if err != nil {
return nil, err
}
ns = append(ns, &NestedBlock{
depth: depth,
content: n,
})
}
}
}
// check if input string is in expected format
if depth != 0 {
return nil, fmt.Errorf("nested slice formatting error %s", sliceStr)
}
return ns, nil
}
// Flatten returns nested int slices in one dimension
func (ns NestedSlice) Flatten() []int {
r := make([]int, 0, len(ns))
for _, nb := range ns {
r = append(r, nb.content)
}
return r
}
// Test cases below
func TestParseNestedSliceSuccess(t *testing.T) {
ns, err := ParseNestedSlice("[[1,2,[3]],4]")
assert.NoError(t, err)
assert.NotNil(t, ns)
assert.Equal(t, 4, len(ns))
assert.Equal(t, 1, ns[0].content)
assert.Equal(t, 2, ns[1].content)
assert.Equal(t, 3, ns[2].content)
assert.Equal(t, 4, ns[3].content)
assert.Equal(t, 2, ns[0].depth)
assert.Equal(t, 2, ns[1].depth)
assert.Equal(t, 3, ns[2].depth)
assert.Equal(t, 1, ns[3].depth)
ns, err = ParseNestedSlice("[[1,2,[3],[4,6]],[4,8],10]")
assert.NoError(t, err)
assert.NotNil(t, ns)
ns, err = ParseNestedSlice("[1,2,3]")
assert.NoError(t, err)
assert.NotNil(t, ns)
for _, nb := range ns {
assert.Equal(t, 1, nb.depth)
}
}
func TestParseNestedSliceFailure(t *testing.T) {
ns, err := ParseNestedSlice("[[1,2,[3]],4")
assert.Error(t, err)
assert.Nil(t, ns)
ns, err = ParseNestedSlice("[[1,2,[3]], 4]")
assert.Error(t, err)
assert.Nil(t, ns)
ns, err = ParseNestedSlice("[[1,2,[3, 4]")
assert.Error(t, err)
assert.Nil(t, ns)
}
func TestFlatten(t *testing.T) {
ns, _ := ParseNestedSlice("[[1,2,[3]],4]")
s := ns.Flatten()
assert.NotEqual(t, 0, len(s))
assert.Equal(t, 1, s[0])
assert.Equal(t, 2, s[1])
assert.Equal(t, 3, s[2])
assert.Equal(t, 4, s[3])
ns, _ = ParseNestedSlice("[[1,2,[3],[4,6]],[4,8],10]")
s = ns.Flatten()
assert.Equal(t, 1, s[0])
assert.Equal(t, 2, s[1])
assert.Equal(t, 3, s[2])
assert.Equal(t, 4, s[3])
assert.Equal(t, 6, s[4])
assert.Equal(t, 4, s[5])
assert.Equal(t, 8, s[6])
assert.Equal(t, 10, s[7])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment