Skip to content

Commit a057bb0

Browse files
authored
[210_7] 实现 set-union! / set-intersection! / set-difference! / set-xor! 函数 #390
1 parent aca7f2b commit a057bb0

File tree

4 files changed

+249
-0
lines changed

4 files changed

+249
-0
lines changed

devel/210_7.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ bin/lint goldfish/srfi/srfi-113.scm
1313
bin/lint tests/goldfish/liii/set-test.scm
1414
```
1515

16+
## 2026/01/28 实现 set-union! / set-intersection! / set-difference! / set-xor! 函数
17+
### What
18+
在 (liii set) 模块中实现 set-union!、set-intersection!、set-difference!、set-xor! 函数,并在测试文件中新增相应的注释和测试用例。
19+
20+
1. 在 goldfish/srfi/srfi-113.scm 中实现以上函数并添加到导出列表
21+
2. 在 goldfish/liii/set.scm 的导出列表中添加以上函数
22+
3. 在 tests/goldfish/liii/set-test.scm 中添加文档注释和测试用例
23+
24+
### Why
25+
这些函数提供集合运算的可变版本,便于在原 set 上进行并集、交集、差集与对称差集计算,减少分配并保持元素来源规则。
26+
27+
### How
28+
1. set-union! 按顺序并入集合,仅在 set1 中不存在时加入
29+
2. set-intersection! 保留同时出现在所有集合中的元素
30+
3. set-difference! 移除出现在其他集合中的元素
31+
4. set-xor! 移除交集元素,并加入只存在于 set2 的元素
32+
5. 在测试中覆盖多集合、元素来源与类型/比较器错误场景
33+
1634
## 2026/01/28 实现 set-union / set-intersection / set-difference / set-xor 函数
1735
### What
1836
在 (liii set) 模块中实现 set-union、set-intersection、set-difference、set-xor 函数,并在测试文件中新增相应的注释和测试用例。

goldfish/liii/set.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
set-any? set-every? set-find set-count set-member set-search! set-map
2727
set-for-each set-fold set-filter set-filter! set-remove set-remove!
2828
set-partition set-partition! set-union set-intersection set-difference set-xor
29+
set-union! set-intersection! set-difference! set-xor!
2930
set-adjoin set-adjoin! set-replace set-replace!
3031
set-delete set-delete! set-delete-all set-delete-all!)
3132

goldfish/srfi/srfi-113.scm

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
set-any? set-every? set-find set-count set-member set-search! set-map
3636
set-for-each set-fold set-filter set-filter! set-remove set-remove!
3737
set-partition set-partition! set-union set-intersection set-difference set-xor
38+
set-union! set-intersection! set-difference! set-xor!
3839
set-adjoin set-adjoin! set-replace set-replace!
3940
set-delete set-delete! set-delete-all set-delete-all!)
4041
(begin
@@ -443,6 +444,71 @@
443444
ht2)
444445
result))
445446

447+
(define (set-union! set1 . sets)
448+
(check-set set1)
449+
(let ((ht1 (set-hash-table set1)))
450+
(for-each
451+
(lambda (s)
452+
(check-set s)
453+
(check-same-comparator set1 s)
454+
(hash-table-for-each
455+
(lambda (k v)
456+
(unless (hash-table-contains? ht1 k)
457+
(set-add! set1 k)))
458+
(set-hash-table s)))
459+
sets)
460+
set1))
461+
462+
(define (set-intersection! set1 . sets)
463+
(check-set set1)
464+
(for-each
465+
(lambda (s)
466+
(check-set s)
467+
(check-same-comparator set1 s))
468+
sets)
469+
(let ((ht1 (set-hash-table set1))
470+
(other-hts (map set-hash-table sets)))
471+
(define (all-contains? key)
472+
(every (lambda (ht) (hash-table-contains? ht key)) other-hts))
473+
(hash-table-for-each
474+
(lambda (k v)
475+
(unless (all-contains? k)
476+
(hash-table-delete! ht1 k)))
477+
ht1)
478+
set1))
479+
480+
(define (set-difference! set1 . sets)
481+
(check-set set1)
482+
(for-each
483+
(lambda (s)
484+
(check-set s)
485+
(check-same-comparator set1 s))
486+
sets)
487+
(let ((ht1 (set-hash-table set1))
488+
(other-hts (map set-hash-table sets)))
489+
(define (any-contains? key)
490+
(any (lambda (ht) (hash-table-contains? ht key)) other-hts))
491+
(hash-table-for-each
492+
(lambda (k v)
493+
(when (any-contains? k)
494+
(hash-table-delete! ht1 k)))
495+
ht1)
496+
set1))
497+
498+
(define (set-xor! set1 set2)
499+
(check-set set1)
500+
(check-set set2)
501+
(check-same-comparator set1 set2)
502+
(let ((ht1 (set-hash-table set1))
503+
(ht2 (set-hash-table set2)))
504+
(hash-table-for-each
505+
(lambda (k v)
506+
(if (hash-table-contains? ht1 k)
507+
(hash-table-delete! ht1 k)
508+
(set-add! set1 k)))
509+
ht2)
510+
set1))
511+
446512
(define (set-adjoin set . elements)
447513
(check-set set)
448514
(let ((new-set (set-copy set)))

tests/goldfish/liii/set-test.scm

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,170 @@ set1, set2 : set
14141414
(check-catch 'type-error (set-xor "not a set" s-1))
14151415
(check-catch 'value-error (set-xor s-1 s-str-ci))
14161416

1417+
#|
1418+
set-union!
1419+
将多个 set 并入 set1(可变操作)。
1420+
1421+
语法
1422+
----
1423+
(set-union! set1 set2 ...)
1424+
1425+
参数
1426+
----
1427+
set1, set2 ... : set
1428+
参与并集的 set。
1429+
1430+
返回值
1431+
------
1432+
返回修改后的 set1,元素来自它们首次出现的 set。
1433+
|#
1434+
1435+
;; 测试 set-union! 基本行为
1436+
(define s-union!-1 (set 1 2 3))
1437+
(define s-union!-result (set-union! s-union!-1 s-2-3-4 s-4-5))
1438+
(check-true (eq? s-union!-result s-union!-1))
1439+
(check (set-size s-union!-1) => 5)
1440+
(check-true (set-contains? s-union!-1 1))
1441+
(check-true (set-contains? s-union!-1 5))
1442+
1443+
;; 测试元素来源(使用大小写不敏感比较器)
1444+
(define s-union!-ci-1 (list->set-with-comparator string-ci-comparator '("Apple")))
1445+
(define s-union!-ci-2 (list->set-with-comparator string-ci-comparator '("apple" "Banana")))
1446+
(define s-union!-ci (set-union! s-union!-ci-1 s-union!-ci-2))
1447+
(check-true (eq? s-union!-ci s-union!-ci-1))
1448+
(check (set-member s-union!-ci "apple" 'not-found) => "Apple")
1449+
(check (set-member s-union!-ci "banana" 'not-found) => "Banana")
1450+
1451+
;; 测试类型与比较器错误
1452+
(check-catch 'type-error (set-union! "not a set" s-1))
1453+
(check-catch 'value-error (set-union! s-1 s-str-ci))
1454+
1455+
#|
1456+
set-intersection!
1457+
就地更新 set1,使其成为多个 set 的交集。
1458+
1459+
语法
1460+
----
1461+
(set-intersection! set1 set2 ...)
1462+
1463+
参数
1464+
----
1465+
set1, set2 ... : set
1466+
参与交集的 set。
1467+
1468+
返回值
1469+
------
1470+
返回修改后的 set1,元素来自第一个 set。
1471+
|#
1472+
1473+
;; 测试 set-intersection! 基本行为
1474+
(define s-inter!-1 (set 1 2 3 4))
1475+
(define s-inter!-result (set-intersection! s-inter!-1 s-2-3-4))
1476+
(check-true (eq? s-inter!-result s-inter!-1))
1477+
(check (set-size s-inter!-1) => 3)
1478+
(check-true (set-contains? s-inter!-1 2))
1479+
(check-true (set-contains? s-inter!-1 3))
1480+
(check-true (set-contains? s-inter!-1 4))
1481+
1482+
;; 测试多集合交集
1483+
(define s-inter!-2 (set 1 2 3 4))
1484+
(set-intersection! s-inter!-2 s-2-3-4 (set 2 3))
1485+
(check (set-size s-inter!-2) => 2)
1486+
(check-true (set-contains? s-inter!-2 2))
1487+
(check-true (set-contains? s-inter!-2 3))
1488+
1489+
;; 测试元素来源(使用大小写不敏感比较器)
1490+
(define s-inter!-ci-1 (list->set-with-comparator string-ci-comparator '("Apple" "Banana")))
1491+
(define s-inter!-ci-2 (list->set-with-comparator string-ci-comparator '("apple" "Pear")))
1492+
(set-intersection! s-inter!-ci-1 s-inter!-ci-2)
1493+
(check (set-member s-inter!-ci-1 "apple" 'not-found) => "Apple")
1494+
(check (set-size s-inter!-ci-1) => 1)
1495+
1496+
;; 测试类型与比较器错误
1497+
(check-catch 'type-error (set-intersection! "not a set" s-1))
1498+
(check-catch 'value-error (set-intersection! s-1 s-str-ci))
1499+
1500+
#|
1501+
set-difference!
1502+
就地更新 set1,使其成为与其余 set 的差集。
1503+
1504+
语法
1505+
----
1506+
(set-difference! set1 set2 ...)
1507+
1508+
参数
1509+
----
1510+
set1, set2 ... : set
1511+
参与差集的 set。
1512+
1513+
返回值
1514+
------
1515+
返回修改后的 set1,元素来自第一个 set。
1516+
|#
1517+
1518+
;; 测试 set-difference! 基本行为
1519+
(define s-diff!-1 (set 1 2 3 4))
1520+
(define s-diff!-result (set-difference! s-diff!-1 s-2-3-4))
1521+
(check-true (eq? s-diff!-result s-diff!-1))
1522+
(check (set-size s-diff!-1) => 1)
1523+
(check-true (set-contains? s-diff!-1 1))
1524+
(check-false (set-contains? s-diff!-1 2))
1525+
1526+
;; 测试多集合差集
1527+
(define s-diff!-2 (set 1 2 3 4 5))
1528+
(set-difference! s-diff!-2 s-2-3-4 s-4-5)
1529+
(check (set-size s-diff!-2) => 1)
1530+
(check-true (set-contains? s-diff!-2 1))
1531+
1532+
;; 测试元素来源(使用大小写不敏感比较器)
1533+
(define s-diff!-ci-1 (list->set-with-comparator string-ci-comparator '("Apple" "Banana")))
1534+
(define s-diff!-ci-2 (list->set-with-comparator string-ci-comparator '("apple")))
1535+
(set-difference! s-diff!-ci-1 s-diff!-ci-2)
1536+
(check (set-size s-diff!-ci-1) => 1)
1537+
(check (set-member s-diff!-ci-1 "banana" 'not-found) => "Banana")
1538+
1539+
;; 测试类型与比较器错误
1540+
(check-catch 'type-error (set-difference! "not a set" s-1))
1541+
(check-catch 'value-error (set-difference! s-1 s-str-ci))
1542+
1543+
#|
1544+
set-xor!
1545+
就地更新 set1,使其成为与 set2 的对称差集。
1546+
1547+
语法
1548+
----
1549+
(set-xor! set1 set2)
1550+
1551+
参数
1552+
----
1553+
set1, set2 : set
1554+
参与对称差集的 set。
1555+
1556+
返回值
1557+
------
1558+
返回修改后的 set1。
1559+
|#
1560+
1561+
;; 测试 set-xor! 基本行为
1562+
(define s-xor!-1 (set 1 2 3))
1563+
(define s-xor!-result (set-xor! s-xor!-1 s-2-3-4))
1564+
(check-true (eq? s-xor!-result s-xor!-1))
1565+
(check (set-size s-xor!-1) => 2)
1566+
(check-true (set-contains? s-xor!-1 1))
1567+
(check-true (set-contains? s-xor!-1 4))
1568+
1569+
;; 测试元素来源(使用大小写不敏感比较器)
1570+
(define s-xor!-ci-1 (list->set-with-comparator string-ci-comparator '("Apple")))
1571+
(define s-xor!-ci-2 (list->set-with-comparator string-ci-comparator '("apple" "Banana")))
1572+
(set-xor! s-xor!-ci-1 s-xor!-ci-2)
1573+
(check (set-size s-xor!-ci-1) => 1)
1574+
(check (set-member s-xor!-ci-1 "banana" 'not-found) => "Banana")
1575+
(check-false (set-contains? s-xor!-ci-1 "apple"))
1576+
1577+
;; 测试类型与比较器错误
1578+
(check-catch 'type-error (set-xor! "not a set" s-1))
1579+
(check-catch 'value-error (set-xor! s-1 s-str-ci))
1580+
14171581
#|
14181582
set->list
14191583
将 set 转换为列表(顺序未指定)。

0 commit comments

Comments
 (0)