Remove Duplicates: compare the text cells show

Excel decides duplicates by what a cell displays, not the value stored:
the same date shown as 3/8/2006 and as Mar 8, 2006 is two values, while
1.01 and 1.02 both shown as 1.0 are duplicates. Remove Duplicates
compared stored values, so it did the opposite in both cases.
This commit is contained in:
nihilist-narwhal
2026-10-10 22:52:59 -05:00
parent 5e22f9b373
commit ce83871f2b
2 changed files with 16 additions and 1 deletions
+4 -1
View File
@@ -691,8 +691,11 @@ fn remove_duplicates(s: &mut Session, p: &Json) -> Result<Json> {
let Some(sh) = cx.wb.sheet(sheet) else { return Ok(()) };
let mut seen = std::collections::HashSet::new();
let mut keep: Vec<u32> = Vec::new();
// Cells are compared by the text they show, as in Excel: the same date in two formats
// isn't a duplicate, while 1.01 and 1.02 shown as 1.0 are.
let shown = |c: CellRef| crate::display::format(&sh.value(c), cx.wb.styles.get(sh.style_id(c)).num_fmt.as_str(), &cx.wb).text;
for row in start..=r.end.row {
let key: Vec<String> = cols.iter().map(|c| sh.value(CellRef::new(row, *c)).display().to_lowercase()).collect();
let key: Vec<String> = cols.iter().map(|c| shown(CellRef::new(row, *c)).to_lowercase()).collect();
if seen.insert(key) {
keep.push(row);
} else {
+12
View File
@@ -615,6 +615,18 @@ fn case_sensitive_sort_puts_lowercase_first() {
assert_eq!(col, ["a", "A", "aB", "Ab", "b", "B"].map(Value::from));
}
#[test]
fn remove_duplicates_compares_shown_text() {
let mut s = s();
s.execute("range.setValues", json!({"range": "A1", "values": [["Date", "Price"], ["2006-03-08", 1.01], ["2006-03-08", 1.02]]})).unwrap();
s.execute("home.numberFormat", json!({"range": "A3", "code": "mmm d, yyyy"})).unwrap();
s.execute("home.numberFormat", json!({"range": "B2:B3", "code": "0.0"})).unwrap();
let r = s.execute("data.removeDuplicates", json!({"range": "A1:A3", "header": true})).unwrap();
assert_eq!(r["removed"], 0);
let r = s.execute("data.removeDuplicates", json!({"range": "B1:B3", "header": true})).unwrap();
assert_eq!(r["removed"], 1);
}
#[test]
fn formatting_and_styles() {
let mut s = s();