| 674 | ) |
| 675 | |
| 676 | def join_tables(self, rows_a: Rows, rows_b: Rows) -> tuple[Columns, Rows]: |
| 677 | ncols = len(self.columns) |
| 678 | |
| 679 | default = ("",) * (ncols - 1) |
| 680 | data_a = {x[0]: x[1:] for x in rows_a} |
| 681 | data_b = {x[0]: x[1:] for x in rows_b} |
| 682 | |
| 683 | if len(data_a) != len(rows_a) or len(data_b) != len(rows_b): |
| 684 | raise ValueError("Duplicate keys") |
| 685 | |
| 686 | # To preserve ordering, use A's keys as is and then add any in B that |
| 687 | # aren't in A |
| 688 | keys = list(data_a.keys()) + [k for k in data_b.keys() if k not in data_a] |
| 689 | rows = [ |
| 690 | self.join_row(k, data_a.get(k, default), data_b.get(k, default)) |
| 691 | for k in keys |
| 692 | ] |
| 693 | if self.join_mode in (JoinMode.CHANGE, JoinMode.CHANGE_ONE_COLUMN): |
| 694 | rows.sort(key=lambda row: abs(float(row[-1])), reverse=True) |
| 695 | |
| 696 | columns = self.join_columns(self.columns) |
| 697 | return columns, rows |
| 698 | |
| 699 | def get_table( |
| 700 | self, base_stats: Stats, head_stats: Stats | None = None |