Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve set functions #154

Merged
merged 1 commit into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 50 additions & 54 deletions evaldo/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -4476,7 +4476,7 @@ var builtins = map[string]*env.Builtin{

"sort!": { // **
Argsn: 1,
Doc: "Accepts a block of values and returns maximal value.",
Doc: "Accepts a block or list and sorts in place in ascending order and returns it.",
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
switch block := arg0.(type) {
case env.Block:
Expand Down Expand Up @@ -5291,49 +5291,22 @@ var builtins = map[string]*env.Builtin{
case env.Block:
switch b2 := arg1.(type) {
case env.Block:
inter := util.UnionOfLists(ps, s1.Series.S, b2.Series.S)
return *env.NewBlock(*env.NewTSeries(inter))
union := util.UnionOfBlocks(ps, s1, b2)
return *env.NewBlock(*env.NewTSeries(union))
default:
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "union")
}
case env.List:
switch secondBlock := arg1.(type) {
case env.Block:
mergedSlice := make([]env.Object, 0)
// Initially fill first block data
for _, v := range s1.Data {
mergedSlice = append(mergedSlice, env.ToRyeValue(v))
}
// If isAvailable is false then it is new value
isAvailable := false
for _, v1 := range secondBlock.Series.S {
isAvailable = false
for _, v2 := range s1.Data {
if env.RyeToRaw(v1) == v2 {
isAvailable = true
break
}
}
// If new value then add in List
if !isAvailable {
mergedSlice = append(mergedSlice, v1)
}
}
// Create list of array
unionSlice := make([]any, 0, len(mergedSlice))
for _, value := range mergedSlice {
unionSlice = append(unionSlice, value)
}
// return List
return *env.NewList(unionSlice)

switch l2 := arg1.(type) {
case env.List:
union := util.UnionOfLists(ps, s1, l2)
return *env.NewList(union)
default:
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "union")
return MakeArgError(ps, 2, []env.Type{env.ListType}, "union")
}
default:
return MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType}, "union")
}

},
},

Expand All @@ -5354,38 +5327,61 @@ var builtins = map[string]*env.Builtin{
case env.Block:
switch b2 := arg1.(type) {
case env.Block:
inter := util.IntersectLists(ps, s1.Series.S, b2.Series.S)
inter := util.IntersectBlocks(ps, s1, b2)
return *env.NewBlock(*env.NewTSeries(inter))
default:
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "intersect")
}
case env.List:
switch secondBlock := arg1.(type) {
case env.Block:
commonSlice := make([]env.Object, 0)
for _, v1 := range s1.Data {
for _, v2 := range secondBlock.Series.S {
// get matching value in both blocks
if env.RyeToRaw(v2) == v1 {
commonSlice = append(commonSlice, v2)
}
}
}
intersectSlice := make([]any, 0, len(commonSlice))
for _, value := range commonSlice {
intersectSlice = append(intersectSlice, value)
}
// return List
return *env.NewList(intersectSlice)
switch l2 := arg1.(type) {
case env.List:
inter := util.IntersectLists(ps, s1, l2)
return *env.NewList(inter)
default:
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "intersect")
return MakeArgError(ps, 2, []env.Type{env.ListType}, "intersect")
}
default:
return MakeArgError(ps, 1, []env.Type{env.StringType, env.BlockType, env.ListType}, "intersect")
}
},
},

"difference": {
Argsn: 2,
Doc: "Finds the difference (values in first but not in second) of two values.",
Pure: true,
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
switch s1 := arg0.(type) {
case env.String:
switch s2 := arg1.(type) {
case env.String:
diff := util.DiffStrings(s1.Value, s2.Value)
return *env.NewString(diff)
default:
return MakeArgError(ps, 2, []env.Type{env.StringType}, "difference")
}
case env.Block:
switch b2 := arg1.(type) {
case env.Block:
diff := util.DiffBlocks(ps, s1, b2)
return *env.NewBlock(*env.NewTSeries(diff))
default:
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "difference")
}
case env.List:
switch l2 := arg1.(type) {
case env.List:
diff := util.DiffLists(ps, s1, l2)
return *env.NewList(diff)
default:
return MakeArgError(ps, 2, []env.Type{env.ListType}, "difference")
}
default:
return MakeArgError(ps, 1, []env.Type{env.StringType, env.BlockType, env.ListType}, "difference")
}
},
},

"str": {
Argsn: 1,
Doc: "Turn Rye value to String.",
Expand Down
55 changes: 41 additions & 14 deletions tests/structures.rye
Original file line number Diff line number Diff line change
Expand Up @@ -209,41 +209,68 @@ section "Working with blocks and lists"
group "union"
mold\nowrap ?union
{ { block } }
; sortorder isn't deterministic so far ... think if it should be
{
equal { union { 8 2 } { 1 9 } |length? } 4 ; sortorder isn't deterministic so far ... think if it should be
equal { union { } { 1 9 } |length? } 2
equal { union { 8 2 } { 1 9 } |sort! } { 1 2 8 9 }
equal { union { 1 2 } { } |sort! } { 1 2 }
equal { union { } { 1 9 } |sort! } { 1 9 }
equal { union { } { } } { }

equal { union list { 1 2 } { 1 2 3 4 } } list { 1 2 3 4 }
equal { union list { 1 2 } { 1 } } list { 1 2 }
equal { union list { 1 2 } { } } list { 1 2 }
equal { union list { } { } } list { }
equal { union list { 1 2 } list { 1 2 3 4 } |sort! } list { 1 2 3 4 }
equal { union list { 1 2 } list { 1 } |sort! } list { 1 2 }
equal { union list { 1 2 } list { } |sort! } list { 1 2 }
equal { union list { } list { 1 2 } |sort! } list { 1 2 }
equal { union list { } list { } } list { }
}
group "intersection"
mold\nowrap ?intersection
{ { block } }
{
equal { intersection { 1 3 5 6 } { 2 3 4 5 } } { 3 5 }
equal { intersection { 1 2 3 } { } } { }
equal { intersection { } { 2 3 4 } } { }
equal { intersection { 1 2 3 } { 4 5 6 } } { }
equal { intersection { } { } } { }

equal { intersection list { 1 3 5 6 } { 2 3 4 5 } } list { 3 5 }
equal { intersection list { } { 2 3 4 } } list { }
equal { intersection list { } { } } list { }
equal { intersection list { 1 3 5 6 } list { 2 3 4 5 } } list { 3 5 }
equal { intersection list { 1 2 3 } list { } } list { }
equal { intersection list { } list { 2 3 4 } } list { }
equal { intersection list { 1 2 3 } list { 4 5 6 } } list { }
equal { intersection list { } list { } } list { }
}
group "difference"
mold\nowrap ?difference
{ { block } }
{
equal { difference "abc" "bc" } "a"
equal { difference "abc" "abc" } ""
equal { difference "abc" "" } "abc"
equal { difference "" "" } ""

equal { difference { 1 3 5 6 } { 2 3 4 5 } } { 1 6 }
equal { difference { 1 2 3 } { } } { 1 2 3 }
equal { difference { } { 2 3 4 } } { }
equal { difference { } { } } { }

equal { difference list { 1 3 5 6 } list { 2 3 4 5 } } list { 1 6 }
equal { difference list { 1 2 3 } list { } } list { 1 2 3 }
equal { difference list { } list { 2 3 4 } } list { }
equal { difference list { } list { } } list { }
}

group "unique"
mold\nowrap ?unique
{ { block string list } }
; result order is not deterministic
{
equal { { 3 2 3 5 3 2 } .list .unique .length? } 3 ; result order is not deterministic list { 3 2 5 }
equal { list { 3 2 3 5 3 2 } .unique |sort! } list { 2 3 5 }
; List
equal { unique list { 1 1 2 2 3 } |length? } 3
equal { unique list { 1 1 2 2 } |length? } 2
equal { unique list { 1 1 2 2 3 } |sort! } list { 1 2 3 }
equal { unique list { 1 1 2 2 } |sort! } list { 1 2 }

; Block
equal { unique { 1 1 2 2 3 } |length? } 3
equal { unique { 1 1 2 2 } |length? } 2
equal { unique { 1 1 2 2 3 } |sort! } { 1 2 3 }
equal { unique { 1 1 2 2 } |sort! } { 1 2 }

; String
equal { unique "aabbc" |length? } 3
Expand Down
88 changes: 76 additions & 12 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package util
import (
"fmt"
"regexp"
"slices"
"strconv"
"strings"

Expand Down Expand Up @@ -203,32 +204,44 @@ func SplitEveryList(s []env.Object, chunkSize int) [][]env.Object {
}

func IntersectStrings(a string, b string) string {
res := ""
set := make(map[rune]bool)
var bu strings.Builder
for _, ch := range a {
if strings.Contains(b, string(ch)) && !strings.Contains(res, string(ch)) {
res = res + string(ch)
if strings.ContainsRune(b, ch) && !set[ch] {
bu.WriteRune(ch)
}
}
return bu.String()
}

func IntersectBlocks(ps *env.ProgramState, a env.Block, b env.Block) []env.Object {
set := make(map[env.Object]bool)
res := make([]env.Object, 0)
for _, v := range a.Series.S {
if ContainsVal(ps, b.Series.S, v) && !set[v] {
res = append(res, v)
}
}
return res
}

func IntersectLists(ps *env.ProgramState, a []env.Object, b []env.Object) []env.Object {
set := make([]env.Object, 0)
for _, v := range a {
if ContainsVal(ps, b, v) && !ContainsVal(ps, set, v) {
set = append(set, v)
func IntersectLists(ps *env.ProgramState, a env.List, b env.List) []any {
set := make(map[any]bool)
res := make([]any, 0)
for _, v := range a.Data {
if slices.Contains(b.Data, v) && !set[v] {
res = append(res, v)
}
}
return set
return res
}

func UnionOfLists(ps *env.ProgramState, a []env.Object, b []env.Object) []env.Object {
func UnionOfBlocks(ps *env.ProgramState, a env.Block, b env.Block) []env.Object {
elementMap := make(map[env.Object]bool)
for _, element := range a {
for _, element := range a.Series.S {
elementMap[element] = true
}
for _, element := range b {
for _, element := range b.Series.S {
elementMap[element] = true
}
mergedSlice := make([]env.Object, 0)
Expand All @@ -238,6 +251,57 @@ func UnionOfLists(ps *env.ProgramState, a []env.Object, b []env.Object) []env.Ob
return mergedSlice
}

func UnionOfLists(ps *env.ProgramState, a env.List, b env.List) []any {
elementMap := make(map[any]bool)
for _, element := range a.Data {
elementMap[element] = true
}
for _, element := range b.Data {
elementMap[element] = true
}
mergedSlice := make([]any, 0)
for element := range elementMap {
mergedSlice = append(mergedSlice, element)
}
return mergedSlice
}

func DiffStrings(a string, b string) string {
set := make(map[rune]bool)
var bu strings.Builder
for _, ch := range a {
if !strings.ContainsRune(b, ch) && !set[ch] {
set[ch] = true
bu.WriteRune(ch)
}
}
return bu.String()
}

func DiffBlocks(ps *env.ProgramState, a env.Block, b env.Block) []env.Object {
set := make(map[env.Object]bool)
res := make([]env.Object, 0)
for _, v := range a.Series.S {
if !ContainsVal(ps, b.Series.S, v) && !set[v] {
set[v] = true
res = append(res, v)
}
}
return res
}

func DiffLists(ps *env.ProgramState, a env.List, b env.List) []any {
set := make(map[any]bool)
res := make([]any, 0)
for _, v := range a.Data {
if !slices.Contains(b.Data, v) && !set[v] {
set[v] = true
res = append(res, v)
}
}
return res
}

func SplitMulti(s string, seps string) []string {
splitter := func(r rune) bool {
return strings.ContainsRune(seps, r)
Expand Down