jointable -n vergleicht Schlüssel als Zahlen, Review Punkt 9 abgeschlossen

This commit is contained in:
wkh
2026-10-30 10:07:48 +01:00
parent 158ce5dee2
commit d6733e737e
5 changed files with 30 additions and 11 deletions
+1
View File
@@ -42,6 +42,7 @@ folgen [Semantic Versioning](https://semver.org/lang/de/). Die Version steht in
- Tabellen, Indexdateien und `substitute` werden über eine temporäre Datei mit `rename` geschrieben; ein Abbruch lässt die alte Datei statt einer halben neuen. - Tabellen, Indexdateien und `substitute` werden über eine temporäre Datei mit `rename` geschrieben; ein Abbruch lässt die alte Datei statt einer halben neuen.
- `index -mb` und `-mi` sortieren nach dem Schlüssel ohne umgebende Leerzeichen, so wie `search` vergleicht. - `index -mb` und `-mi` sortieren nach dem Schlüssel ohne umgebende Leerzeichen, so wie `search` vergleicht.
- `sorttable -r` kehrte auch die Reihenfolge gleicher Schlüssel um; sie bleibt jetzt erhalten. - `sorttable -r` kehrte auch die Reihenfolge gleicher Schlüssel um; sie bleibt jetzt erhalten.
- `jointable -n` wurde stillschweigend ignoriert. Wie in der Man-Page vergleicht es die Schlüssel jetzt als Zahlen (`01`, `1` und ` 1.0` passen zusammen).
- Spaltennamen, die `justify` mit Leerzeichen aufgefüllt hat, wurden nicht mehr gefunden: `column Name` lieferte eine leere Spalte, `index` brach ab. Leerraum um die Namen im Kopf zählt jetzt nicht mehr. - Spaltennamen, die `justify` mit Leerzeichen aufgefüllt hat, wurden nicht mehr gefunden: `column Name` lieferte eine leere Spalte, `index` brach ab. Leerraum um die Namen im Kopf zählt jetzt nicht mehr.
## [0.7.0] - 2026-10-12 ## [0.7.0] - 2026-10-12
+1 -1
View File
@@ -13,7 +13,7 @@ sind nach dem Handbuch neu geschrieben.
mise trust # einmal nach dem Clone: mise.toml freigeben mise trust # einmal nach dem Clone: mise.toml freigeben
mise install # Ruby 3.4 mise install # Ruby 3.4
mise run install # legt die Symlinks row, column, total ... in bin/ an mise run install # legt die Symlinks row, column, total ... in bin/ an
mise run test # 131 Tests und die Beispiele aus dem Handbuch mise run test # 132 Tests und die Beispiele aus dem Handbuch
``` ```
Ohne `mise trust` brechen in einem frisch geklonten Ordner alle `mise`-Befehle ab. Ohne `mise trust` brechen in einem frisch geklonten Ordner alle `mise`-Befehle ab.
+10 -4
View File
@@ -67,10 +67,16 @@ gelesen), 3 (Fehler als eine Zeile, `RDB_DEBUG=1` für den Backtrace), 4 (`EDITO
Argumenten, Editorfehler wird gemeldet), 5 (Satz wird in jedem Fall zurückgeschrieben), Argumenten, Editorfehler wird gemeldet), 5 (Satz wird in jedem Fall zurückgeschrieben),
6 (`Rdb.check_cells!`), 7 (`Rdb.write_file`: temporäre Datei plus `rename`) und 8 6 (`Rdb.check_cells!`), 7 (`Rdb.write_file`: temporäre Datei plus `rename`) und 8
(Sortierschlüssel ohne Leerzeichen) sind behoben, jeweils mit Test. (Sortierschlüssel ohne Leerzeichen) sind behoben, jeweils mit Test.
Bei 9 ist nur `sorttable -r` behoben. Bewusst offen: `-nrf` gilt global (so beschreibt es
das Handbuch), `jointable -n` ist unklar spezifiziert, `1e3` als Zahl und die Zeile aus Bei 9 sind `sorttable -r` (stabil) und `jointable -n` (Schlüssel als Zahlen, wie in der
leeren Zellen als „gelöscht“ sind Eigenheiten des Formats. Bei 8 bleibt `-x` (Faltung) beim Man-Page) behoben. Bleibt so (Entscheidung 2026-10-30):
Index ohne Entsprechung in der Suche offen. - `-nrf` gilt für alle Spalten: laut Man-Page reicht `sorttable` die Optionen an `sort`
weiter, Optionen pro Spalte gibt es im Original nicht.
- `1e3` ist keine Zahl: sonst würden Spalten mit Codes wie `2E5` numerisch.
- Eine Zeile aus lauter leeren Zellen gilt als gelöscht: so arbeitet `delete` im Format.
Offen bei 8: `index -x` (gefaltet) hat in `search` ohne `-x` kein Gegenstück, weil die
`.i`-Datei die Faltung nicht vermerkt. Das bräuchte eine Markierung im Indexkopf.
## Verbesserungspotential ## Verbesserungspotential
+8 -6
View File
@@ -96,7 +96,7 @@ end
Rdb.register('jointable', 'Join two tables into one where keys match', Rdb.register('jointable', 'Join two tables into one where keys match',
'jointable [-a[1|2]] [-j[1|2] column]... [-n] [-] table1 [table2]') do |args| 'jointable [-a[1|2]] [-j[1|2] column]... [-n] [-] table1 [table2]') do |args|
all1 = all2 = false all1 = all2 = numeric = false
k1 = k2 = nil k1 = k2 = nil
files = [] files = []
until args.empty? until args.empty?
@@ -108,7 +108,7 @@ Rdb.register('jointable', 'Join two tables into one where keys match',
when '-j' then k1 = k2 = args.shift when '-j' then k1 = k2 = args.shift
when '-j1' then k1 = args.shift when '-j1' then k1 = args.shift
when '-j2' then k2 = args.shift when '-j2' then k2 = args.shift
when '-n' then nil when '-n' then numeric = true
else files << a else files << a
end end
end end
@@ -119,13 +119,15 @@ Rdb.register('jointable', 'Join two tables into one where keys match',
i1 = k1 ? t1.index_of(k1) : 0 i1 = k1 ? t1.index_of(k1) : 0
i2 = k2 ? t2.index_of(k2) : 0 i2 = k2 ? t2.index_of(k2) : 0
keep2 = (0...t2.head.size).to_a - [i2] keep2 = (0...t2.head.size).to_a - [i2]
# -n compares keys as numbers: 01, 1 and " 1.0" are the same key
key = ->(v) { numeric && numeric?(v) ? Rdb.decimal(v) : v }
by_key = Hash.new { |h, k| h[k] = [] } by_key = Hash.new { |h, k| h[k] = [] }
t2.rows.each { |r| by_key[r[i2]] << r } t2.rows.each { |r| by_key[key.(r[i2])] << r }
used = {} used = {}
out = [] out = []
t1.rows.each do |r| t1.rows.each do |r|
if (m = by_key[r[i1]]).any? if (m = by_key.fetch(key.(r[i1]), [])).any?
used[r[i1]] = true used[key.(r[i1])] = true
m.each { |r2| out << r + keep2.map { |i| r2[i] } } m.each { |r2| out << r + keep2.map { |i| r2[i] } }
elsif all1 elsif all1
out << r + [''] * keep2.size out << r + [''] * keep2.size
@@ -133,7 +135,7 @@ Rdb.register('jointable', 'Join two tables into one where keys match',
end end
if all2 if all2
t2.rows.each do |r2| t2.rows.each do |r2|
next if used[r2[i2]] next if used[key.(r2[i2])]
blank = [''] * t1.head.size blank = [''] * t1.head.size
blank[i1] = r2[i2] blank[i1] = r2[i2]
+10
View File
@@ -961,3 +961,13 @@ class ExactnessTest < RdbCase
assert_equal 'v500', data_obj.row_at(data_obj.rows.last.from).cells[1] assert_equal 'v500', data_obj.row_at(data_obj.rows.last.from).cells[1]
end end
end end
class JoinNumericTest < RdbCase
def test_jointable_n_matches_keys_as_numbers
write('j1', "K\tA\n-\t-\n01\tx\n 2\ty\n3\tz\n")
write('j2', "K\tB\n-\t-\n1\tp\n2.0\tq\n")
assert_empty data(rdb('jointable', 'j1', 'j2'))
assert_equal [%w[01 x p], [' 2', 'y', 'q']], data(rdb('jointable', '-n', 'j1', 'j2'))
assert_equal 3, data(rdb('jointable', '-n', '-a1', 'j1', 'j2')).size
end
end