Skip to content

Commit 44d1c83

Browse files
authored
Merge pull request #154 from rokostik/improve-set-functions
Improve set functions
2 parents ffb2521 + 96037b0 commit 44d1c83

File tree

3 files changed

+167
-80
lines changed

3 files changed

+167
-80
lines changed

evaldo/builtins.go

+50-54
Original file line numberDiff line numberDiff line change
@@ -4476,7 +4476,7 @@ var builtins = map[string]*env.Builtin{
44764476

44774477
"sort!": { // **
44784478
Argsn: 1,
4479-
Doc: "Accepts a block of values and returns maximal value.",
4479+
Doc: "Accepts a block or list and sorts in place in ascending order and returns it.",
44804480
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
44814481
switch block := arg0.(type) {
44824482
case env.Block:
@@ -5291,49 +5291,22 @@ var builtins = map[string]*env.Builtin{
52915291
case env.Block:
52925292
switch b2 := arg1.(type) {
52935293
case env.Block:
5294-
inter := util.UnionOfLists(ps, s1.Series.S, b2.Series.S)
5295-
return *env.NewBlock(*env.NewTSeries(inter))
5294+
union := util.UnionOfBlocks(ps, s1, b2)
5295+
return *env.NewBlock(*env.NewTSeries(union))
52965296
default:
52975297
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "union")
52985298
}
52995299
case env.List:
5300-
switch secondBlock := arg1.(type) {
5301-
case env.Block:
5302-
mergedSlice := make([]env.Object, 0)
5303-
// Initially fill first block data
5304-
for _, v := range s1.Data {
5305-
mergedSlice = append(mergedSlice, env.ToRyeValue(v))
5306-
}
5307-
// If isAvailable is false then it is new value
5308-
isAvailable := false
5309-
for _, v1 := range secondBlock.Series.S {
5310-
isAvailable = false
5311-
for _, v2 := range s1.Data {
5312-
if env.RyeToRaw(v1) == v2 {
5313-
isAvailable = true
5314-
break
5315-
}
5316-
}
5317-
// If new value then add in List
5318-
if !isAvailable {
5319-
mergedSlice = append(mergedSlice, v1)
5320-
}
5321-
}
5322-
// Create list of array
5323-
unionSlice := make([]any, 0, len(mergedSlice))
5324-
for _, value := range mergedSlice {
5325-
unionSlice = append(unionSlice, value)
5326-
}
5327-
// return List
5328-
return *env.NewList(unionSlice)
5329-
5300+
switch l2 := arg1.(type) {
5301+
case env.List:
5302+
union := util.UnionOfLists(ps, s1, l2)
5303+
return *env.NewList(union)
53305304
default:
5331-
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "union")
5305+
return MakeArgError(ps, 2, []env.Type{env.ListType}, "union")
53325306
}
53335307
default:
53345308
return MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType}, "union")
53355309
}
5336-
53375310
},
53385311
},
53395312

@@ -5354,38 +5327,61 @@ var builtins = map[string]*env.Builtin{
53545327
case env.Block:
53555328
switch b2 := arg1.(type) {
53565329
case env.Block:
5357-
inter := util.IntersectLists(ps, s1.Series.S, b2.Series.S)
5330+
inter := util.IntersectBlocks(ps, s1, b2)
53585331
return *env.NewBlock(*env.NewTSeries(inter))
53595332
default:
53605333
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "intersect")
53615334
}
53625335
case env.List:
5363-
switch secondBlock := arg1.(type) {
5364-
case env.Block:
5365-
commonSlice := make([]env.Object, 0)
5366-
for _, v1 := range s1.Data {
5367-
for _, v2 := range secondBlock.Series.S {
5368-
// get matching value in both blocks
5369-
if env.RyeToRaw(v2) == v1 {
5370-
commonSlice = append(commonSlice, v2)
5371-
}
5372-
}
5373-
}
5374-
intersectSlice := make([]any, 0, len(commonSlice))
5375-
for _, value := range commonSlice {
5376-
intersectSlice = append(intersectSlice, value)
5377-
}
5378-
// return List
5379-
return *env.NewList(intersectSlice)
5336+
switch l2 := arg1.(type) {
5337+
case env.List:
5338+
inter := util.IntersectLists(ps, s1, l2)
5339+
return *env.NewList(inter)
53805340
default:
5381-
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "intersect")
5341+
return MakeArgError(ps, 2, []env.Type{env.ListType}, "intersect")
53825342
}
53835343
default:
53845344
return MakeArgError(ps, 1, []env.Type{env.StringType, env.BlockType, env.ListType}, "intersect")
53855345
}
53865346
},
53875347
},
53885348

5349+
"difference": {
5350+
Argsn: 2,
5351+
Doc: "Finds the difference (values in first but not in second) of two values.",
5352+
Pure: true,
5353+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
5354+
switch s1 := arg0.(type) {
5355+
case env.String:
5356+
switch s2 := arg1.(type) {
5357+
case env.String:
5358+
diff := util.DiffStrings(s1.Value, s2.Value)
5359+
return *env.NewString(diff)
5360+
default:
5361+
return MakeArgError(ps, 2, []env.Type{env.StringType}, "difference")
5362+
}
5363+
case env.Block:
5364+
switch b2 := arg1.(type) {
5365+
case env.Block:
5366+
diff := util.DiffBlocks(ps, s1, b2)
5367+
return *env.NewBlock(*env.NewTSeries(diff))
5368+
default:
5369+
return MakeArgError(ps, 2, []env.Type{env.BlockType}, "difference")
5370+
}
5371+
case env.List:
5372+
switch l2 := arg1.(type) {
5373+
case env.List:
5374+
diff := util.DiffLists(ps, s1, l2)
5375+
return *env.NewList(diff)
5376+
default:
5377+
return MakeArgError(ps, 2, []env.Type{env.ListType}, "difference")
5378+
}
5379+
default:
5380+
return MakeArgError(ps, 1, []env.Type{env.StringType, env.BlockType, env.ListType}, "difference")
5381+
}
5382+
},
5383+
},
5384+
53895385
"str": {
53905386
Argsn: 1,
53915387
Doc: "Turn Rye value to String.",

tests/structures.rye

+41-14
Original file line numberDiff line numberDiff line change
@@ -209,41 +209,68 @@ section "Working with blocks and lists"
209209
group "union"
210210
mold\nowrap ?union
211211
{ { block } }
212+
; sortorder isn't deterministic so far ... think if it should be
212213
{
213-
equal { union { 8 2 } { 1 9 } |length? } 4 ; sortorder isn't deterministic so far ... think if it should be
214-
equal { union { } { 1 9 } |length? } 2
214+
equal { union { 8 2 } { 1 9 } |sort! } { 1 2 8 9 }
215+
equal { union { 1 2 } { } |sort! } { 1 2 }
216+
equal { union { } { 1 9 } |sort! } { 1 9 }
215217
equal { union { } { } } { }
216218

217-
equal { union list { 1 2 } { 1 2 3 4 } } list { 1 2 3 4 }
218-
equal { union list { 1 2 } { 1 } } list { 1 2 }
219-
equal { union list { 1 2 } { } } list { 1 2 }
220-
equal { union list { } { } } list { }
219+
equal { union list { 1 2 } list { 1 2 3 4 } |sort! } list { 1 2 3 4 }
220+
equal { union list { 1 2 } list { 1 } |sort! } list { 1 2 }
221+
equal { union list { 1 2 } list { } |sort! } list { 1 2 }
222+
equal { union list { } list { 1 2 } |sort! } list { 1 2 }
223+
equal { union list { } list { } } list { }
221224
}
222225
group "intersection"
223226
mold\nowrap ?intersection
224227
{ { block } }
225228
{
226229
equal { intersection { 1 3 5 6 } { 2 3 4 5 } } { 3 5 }
230+
equal { intersection { 1 2 3 } { } } { }
227231
equal { intersection { } { 2 3 4 } } { }
232+
equal { intersection { 1 2 3 } { 4 5 6 } } { }
228233
equal { intersection { } { } } { }
229234

230-
equal { intersection list { 1 3 5 6 } { 2 3 4 5 } } list { 3 5 }
231-
equal { intersection list { } { 2 3 4 } } list { }
232-
equal { intersection list { } { } } list { }
235+
equal { intersection list { 1 3 5 6 } list { 2 3 4 5 } } list { 3 5 }
236+
equal { intersection list { 1 2 3 } list { } } list { }
237+
equal { intersection list { } list { 2 3 4 } } list { }
238+
equal { intersection list { 1 2 3 } list { 4 5 6 } } list { }
239+
equal { intersection list { } list { } } list { }
240+
}
241+
group "difference"
242+
mold\nowrap ?difference
243+
{ { block } }
244+
{
245+
equal { difference "abc" "bc" } "a"
246+
equal { difference "abc" "abc" } ""
247+
equal { difference "abc" "" } "abc"
248+
equal { difference "" "" } ""
249+
250+
equal { difference { 1 3 5 6 } { 2 3 4 5 } } { 1 6 }
251+
equal { difference { 1 2 3 } { } } { 1 2 3 }
252+
equal { difference { } { 2 3 4 } } { }
253+
equal { difference { } { } } { }
254+
255+
equal { difference list { 1 3 5 6 } list { 2 3 4 5 } } list { 1 6 }
256+
equal { difference list { 1 2 3 } list { } } list { 1 2 3 }
257+
equal { difference list { } list { 2 3 4 } } list { }
258+
equal { difference list { } list { } } list { }
233259
}
234260

235261
group "unique"
236262
mold\nowrap ?unique
237263
{ { block string list } }
264+
; result order is not deterministic
238265
{
239-
equal { { 3 2 3 5 3 2 } .list .unique .length? } 3 ; result order is not deterministic list { 3 2 5 }
266+
equal { list { 3 2 3 5 3 2 } .unique |sort! } list { 2 3 5 }
240267
; List
241-
equal { unique list { 1 1 2 2 3 } |length? } 3
242-
equal { unique list { 1 1 2 2 } |length? } 2
268+
equal { unique list { 1 1 2 2 3 } |sort! } list { 1 2 3 }
269+
equal { unique list { 1 1 2 2 } |sort! } list { 1 2 }
243270

244271
; Block
245-
equal { unique { 1 1 2 2 3 } |length? } 3
246-
equal { unique { 1 1 2 2 } |length? } 2
272+
equal { unique { 1 1 2 2 3 } |sort! } { 1 2 3 }
273+
equal { unique { 1 1 2 2 } |sort! } { 1 2 }
247274

248275
; String
249276
equal { unique "aabbc" |length? } 3

util/util.go

+76-12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package util
44
import (
55
"fmt"
66
"regexp"
7+
"slices"
78
"strconv"
89
"strings"
910

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

205206
func IntersectStrings(a string, b string) string {
206-
res := ""
207+
set := make(map[rune]bool)
208+
var bu strings.Builder
207209
for _, ch := range a {
208-
if strings.Contains(b, string(ch)) && !strings.Contains(res, string(ch)) {
209-
res = res + string(ch)
210+
if strings.ContainsRune(b, ch) && !set[ch] {
211+
bu.WriteRune(ch)
210212
}
211213
}
214+
return bu.String()
215+
}
212216

217+
func IntersectBlocks(ps *env.ProgramState, a env.Block, b env.Block) []env.Object {
218+
set := make(map[env.Object]bool)
219+
res := make([]env.Object, 0)
220+
for _, v := range a.Series.S {
221+
if ContainsVal(ps, b.Series.S, v) && !set[v] {
222+
res = append(res, v)
223+
}
224+
}
213225
return res
214226
}
215227

216-
func IntersectLists(ps *env.ProgramState, a []env.Object, b []env.Object) []env.Object {
217-
set := make([]env.Object, 0)
218-
for _, v := range a {
219-
if ContainsVal(ps, b, v) && !ContainsVal(ps, set, v) {
220-
set = append(set, v)
228+
func IntersectLists(ps *env.ProgramState, a env.List, b env.List) []any {
229+
set := make(map[any]bool)
230+
res := make([]any, 0)
231+
for _, v := range a.Data {
232+
if slices.Contains(b.Data, v) && !set[v] {
233+
res = append(res, v)
221234
}
222235
}
223-
return set
236+
return res
224237
}
225238

226-
func UnionOfLists(ps *env.ProgramState, a []env.Object, b []env.Object) []env.Object {
239+
func UnionOfBlocks(ps *env.ProgramState, a env.Block, b env.Block) []env.Object {
227240
elementMap := make(map[env.Object]bool)
228-
for _, element := range a {
241+
for _, element := range a.Series.S {
229242
elementMap[element] = true
230243
}
231-
for _, element := range b {
244+
for _, element := range b.Series.S {
232245
elementMap[element] = true
233246
}
234247
mergedSlice := make([]env.Object, 0)
@@ -238,6 +251,57 @@ func UnionOfLists(ps *env.ProgramState, a []env.Object, b []env.Object) []env.Ob
238251
return mergedSlice
239252
}
240253

254+
func UnionOfLists(ps *env.ProgramState, a env.List, b env.List) []any {
255+
elementMap := make(map[any]bool)
256+
for _, element := range a.Data {
257+
elementMap[element] = true
258+
}
259+
for _, element := range b.Data {
260+
elementMap[element] = true
261+
}
262+
mergedSlice := make([]any, 0)
263+
for element := range elementMap {
264+
mergedSlice = append(mergedSlice, element)
265+
}
266+
return mergedSlice
267+
}
268+
269+
func DiffStrings(a string, b string) string {
270+
set := make(map[rune]bool)
271+
var bu strings.Builder
272+
for _, ch := range a {
273+
if !strings.ContainsRune(b, ch) && !set[ch] {
274+
set[ch] = true
275+
bu.WriteRune(ch)
276+
}
277+
}
278+
return bu.String()
279+
}
280+
281+
func DiffBlocks(ps *env.ProgramState, a env.Block, b env.Block) []env.Object {
282+
set := make(map[env.Object]bool)
283+
res := make([]env.Object, 0)
284+
for _, v := range a.Series.S {
285+
if !ContainsVal(ps, b.Series.S, v) && !set[v] {
286+
set[v] = true
287+
res = append(res, v)
288+
}
289+
}
290+
return res
291+
}
292+
293+
func DiffLists(ps *env.ProgramState, a env.List, b env.List) []any {
294+
set := make(map[any]bool)
295+
res := make([]any, 0)
296+
for _, v := range a.Data {
297+
if !slices.Contains(b.Data, v) && !set[v] {
298+
set[v] = true
299+
res = append(res, v)
300+
}
301+
}
302+
return res
303+
}
304+
241305
func SplitMulti(s string, seps string) []string {
242306
splitter := func(r rune) bool {
243307
return strings.ContainsRune(seps, r)

0 commit comments

Comments
 (0)