雜記 › 生活隨筆 › 四個開關預設開著哪三個:文本集合運算的摺疊口徑、代表元與去重短路實測

四個開關預設開著哪三個:文本集合運算的摺疊口徑、代表元與去重短路實測

文本集合運算頁四個開關預設開著去空格、忽略空行、結果去重三個,只有區分大小寫不勾。實測五步判定順序、toLowerCase摺疊檔與代表元取首現寫法,關掉去重後並集從3行漲到6行,守恆與冪等同時翻面。

四個開關裡,預設開著的是哪三個

四個開關的預設態我沒核實過——起因是一輪並集結果比預期多出一截,回頭發現「結果去重」被取消過勾選。於是把模板拆下來:本體 8641 位元組、215 個換行,腳本正文 4630 個碼元按 LF 切出 146 段,一字不改跑在 DOM 樁上。讀出來的 markup:opt-trim、opt-skip-empty、opt-dedup 三條都帶 checked,唯獨 opt-case 不帶——預設就是「去首尾空格 + 忽略空行 + 結果去重 + 不區分大小寫」,currentOp 初值逐字是 intersection。名單樣本一律是 DEMO- 前綴的虛構編號。

這套預設值在 文本集合運算 頁管著三件事:大小寫檔位決定 Apple 和 apple 算不算同一個元素;trim 與忽略空行決定「看著非空」的行算不算元素;結果去重不只作用在結果層,還喂著 parseSet 的第 5 步。整頁 textarea 2 個、tab 3 個、checkbox 4 個、下拉 0 個,動哪個都全量重算。

parseSet 的五步順序,與「代表元取首現」

順序是:按換行切開 → trim 開著就改寫該行 → 改寫後是空字串且忽略空行開著就跳過 → key 取該行或它的 toLowerCase → 去重開著才查 seen → 最後 push 的是改寫後但未摺疊的那一行。最後半句就是代表元規則:「Apple / apple / APPLE」3 行預設檔 cnt-a=1,數組就是 ["Apple"];勾上區分大小寫才變 3。

A=「Apple / apple / DEMO-7」、B=「apple / Apple / DEMO-8」,交集是 ["Apple"],取 A 側首現寫法;兩側對調,結果變成 ["apple"]。並集先把整個 A 的首現序推完,再接 B 裡沒出現過的。「差集有方向」那套講法在舊文 對比兩份名單 寫過,本篇不重講。

摺疊只用 toLowerCase() 一個函數

模板裡 toLowerCase 命中 7 次、toLocaleLowerCase 與 toUpperCase 各 0 次,後果分三類。一類正常並:ß 與 ẞ 都摺成 U+00DF 同 key,「ß / ẞ / ss / ß」4 行得 cnt-a=2,ss 摺後是 2 個碼元、不並。二類不並:İ 摺成 i 加 U+0307 組合點、共 2 個碼元,UTF-8 從 2 位元組變 3 位元組,所以 İ 與 I、i 的 key 不相等——「İ / I / i / İIII」4 行預設檔 cnt-a=3,數組是 ["İ", "I", "İIII"],I 與 i 並成一個。三類:開爾文符號 U+212A 摺成 k,「U+212A / K / k」3 行 cnt-a=1,代表元取首現那個 3 位元組的原始寫法;ẛ 摺完原地不動。「預設不區分大小寫」不等於所有變體都並上。

關掉結果去重,那條短路整條失效

parseSet 裡那行 if (dedup && seen.has(key)) continue 在去重關時整條短路,摺疊層與結果層去重一起失效。固定 A=「apple / Apple / APPLE / DEMO-X」4 行(前三行摺疊後同 key)、B=「apple / BANANA」2 行,只切這一個開關:

檔位cnt-a交集差集並集
去重開(預設)2113
去重關4316

差集兩檔都是 1,因為 A 裡不在 B 的只有 DEMO-X;交集 1 漲到 3 是 apple 三種寫法全留;並集 3 漲到 6,那塊 innerHTML 實測 542 碼元。規模版:A、B 各 1000 行、重疊 500,去重開並集 1500,正好 1000+1000−500;關掉變 2000,守恆差 500。所以列表頁 intro「合併兩個列表並去重(A∪B)」與頁面說明的「合併去重」只在勾選著去重時成立,引用並集計數必須註明檔位。

把結果整段貼回 A 再算:去重開時三檔第 2 輪與第 1 輪逐字相同;去重關時並集不收斂,連貼 4 輪 cnt-r 走 6、8、10、12,每輪淨增的 2 行恰好等於 cnt-b。

只切「結果去重」:A 4 行、B 2 行 去重開 cnt-a 2、交 1、差 1、並 3 去重關 cnt-a 4、交 3、差 1、並 6,innerHTML 542 貼回 A 連跑並集(關) cnt-r 6、8、10、12,每輪淨增 2

圖 1:守恆與冪等都掛在同一個勾選框上

cnt-a 報的不是輸入框的行數

三個統計格顯示的都是 parseSet 之後的數組長度,不是 textarea 的行數。「段數」指按換行切開的份數(B 留空,其餘預設):

輸入(A 側)段數非空行預設 cnt-a忽略空行關
兩行編號、無尾隨換行2222
同兩行、末尾多一個換行3223
兩行編號加中間空行與尾隨換行4223
中間一行只有 2 個全形空格 U+30003323
4 行純空白(空格、製表符、全形空格、NBSP)4401

尾隨換行多出的空段,只在關掉忽略空行後才被計成元素;4 行全空白在預設檔 cnt-a=0,整個 A 變空集,「非空行=4」與「cnt-a=0」同屏。NBSP(U+00A0)與 BOM(U+FEFF)都被 trim 清零。

空集合 ∅ 那一支,和沒被清掉的上一輪

結果數組長度為零時腳本連做三件事:結果卡 display 成 none、空態塊顯示、文案覆寫成「運算結果為空集合 ∅」——這句 10 個碼元、28 位元組,∅ 是 U+2205、佔 1 碼元 3 位元組。模板末尾裸調的那次 calc 在首屏就把兩個空框推進這個分支,markup 裡那句 15 碼元的「請在上方輸入集合元素後自動計算」在被看見之前就遭覆寫,此後沒有任何程式碼寫回。

∅ 分支還是不清空結果區的 innerHTML:先算出 1 行結果(innerHTML 長 94 碼元),再改輸入讓交集變 ∅,cnt-r 歸 0、結果卡已隱藏,此時點「複製結果」仍帶走上一輪那 1 行 DEMO-0001——隱藏不等於清空。escHtml 按 &、<、>、" 四組順序替換(& 排第一,保住往返),<b> 行顯示與複製都是字面 <b>;「<b> / a&b / "q"」3 行樣本 innerHTML 284 碼元,複製串 11 碼元、含 2 個換行。500 行結果的 innerHTML 實測 47892 碼元、序號佔 1392 碼元、末行 #500;scrollHeight 未實測——本次全程純 Node,沒有排版引擎。這些檔位只屬於本頁程式碼,別外推成所有集合運算工具都長這樣。

FAQ

Q:並集行數比名單的元素數還多,是頁面出錯了嗎?

不是。先核對 opt-dedup 勾選框狀態,再對照上面那張兩檔表。

Q:Apple 和 apple 都在,最後留下哪一個?

留 A 側首現的原始寫法,對調後得 ["apple"]。前提是區分大小寫沒勾。

Q:只想去重、不做交並差呢?

另一頁 文本排序去重 更貼近這個需求;它自己的摺疊口徑這次沒測,不替它下結論。

📎 相關文章

奶奶要連點三下才出來:親戚關係計算器 36 條規則與 11110 條鏈的兜底實測 2026-11-07 口算題卡每張 A4 能排多少題:字號、頁邊距與資訊欄怎麼改分頁 2026-11-03 同一串 23 位元組的內容切換 4 個糾錯等級:這一頁自己寫的二維碼編碼器走到了哪一步 2026-10-30 幀間隔填 137 ms,成品每幀其實停 140 ms:tick 量化、4096 頁填充與跟著第一張走的畫布 2026-10-30 拼豆圖紙的色號是怎麼挑出來的:開一次抖動,1024 格裡有 150 格被改寫 2026-10-30