|
|
|
@ -103,16 +103,19 @@ export function mergeTablesIntoModel(dst?: TableModel, ...tables: TableModel[]): |
|
|
|
|
const columnNames: { [key: string]: any } = {}; |
|
|
|
|
|
|
|
|
|
// Union of all non-value columns
|
|
|
|
|
const columnsUnion = tables.slice().reduce((acc, series) => { |
|
|
|
|
series.columns.forEach(col => { |
|
|
|
|
const { text } = col; |
|
|
|
|
if (columnNames[text] === undefined) { |
|
|
|
|
columnNames[text] = acc.length; |
|
|
|
|
acc.push(col); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
return acc; |
|
|
|
|
}, []); |
|
|
|
|
const columnsUnion = tables.slice().reduce( |
|
|
|
|
(acc, series) => { |
|
|
|
|
series.columns.forEach(col => { |
|
|
|
|
const { text } = col; |
|
|
|
|
if (columnNames[text] === undefined) { |
|
|
|
|
columnNames[text] = acc.length; |
|
|
|
|
acc.push(col); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
return acc; |
|
|
|
|
}, |
|
|
|
|
[] as MutableColumn[] |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Map old column index to union index per series, e.g.,
|
|
|
|
|
// given columnNames {A: 0, B: 1} and
|
|
|
|
@ -120,51 +123,57 @@ export function mergeTablesIntoModel(dst?: TableModel, ...tables: TableModel[]): |
|
|
|
|
const columnIndexMapper = tables.map(series => series.columns.map(col => columnNames[col.text])); |
|
|
|
|
|
|
|
|
|
// Flatten rows of all series and adjust new column indexes
|
|
|
|
|
const flattenedRows = tables.reduce((acc, series, seriesIndex) => { |
|
|
|
|
const mapper = columnIndexMapper[seriesIndex]; |
|
|
|
|
series.rows.forEach(row => { |
|
|
|
|
const alteredRow: any[] = []; |
|
|
|
|
// Shifting entries according to index mapper
|
|
|
|
|
mapper.forEach((to, from) => { |
|
|
|
|
alteredRow[to] = row[from]; |
|
|
|
|
const flattenedRows = tables.reduce( |
|
|
|
|
(acc, series, seriesIndex) => { |
|
|
|
|
const mapper = columnIndexMapper[seriesIndex]; |
|
|
|
|
series.rows.forEach(row => { |
|
|
|
|
const alteredRow: MutableColumn[] = []; |
|
|
|
|
// Shifting entries according to index mapper
|
|
|
|
|
mapper.forEach((to, from) => { |
|
|
|
|
alteredRow[to] = row[from]; |
|
|
|
|
}); |
|
|
|
|
acc.push(alteredRow); |
|
|
|
|
}); |
|
|
|
|
acc.push(alteredRow); |
|
|
|
|
}); |
|
|
|
|
return acc; |
|
|
|
|
}, []); |
|
|
|
|
return acc; |
|
|
|
|
}, |
|
|
|
|
[] as MutableColumn[][] |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Merge rows that have same values for columns
|
|
|
|
|
const mergedRows: { [key: string]: any } = {}; |
|
|
|
|
|
|
|
|
|
const compactedRows = flattenedRows.reduce((acc, row, rowIndex) => { |
|
|
|
|
if (!mergedRows[rowIndex]) { |
|
|
|
|
// Look from current row onwards
|
|
|
|
|
let offset = rowIndex + 1; |
|
|
|
|
// More than one row can be merged into current row
|
|
|
|
|
while (offset < flattenedRows.length) { |
|
|
|
|
// Find next row that could be merged
|
|
|
|
|
const match = _.findIndex(flattenedRows, otherRow => areRowsMatching(columnsUnion, row, otherRow), offset); |
|
|
|
|
if (match > -1) { |
|
|
|
|
const matchedRow = flattenedRows[match]; |
|
|
|
|
// Merge values from match into current row if there is a gap in the current row
|
|
|
|
|
for (let columnIndex = 0; columnIndex < columnsUnion.length; columnIndex++) { |
|
|
|
|
if (row[columnIndex] === undefined && matchedRow[columnIndex] !== undefined) { |
|
|
|
|
row[columnIndex] = matchedRow[columnIndex]; |
|
|
|
|
const compactedRows = flattenedRows.reduce( |
|
|
|
|
(acc, row, rowIndex) => { |
|
|
|
|
if (!mergedRows[rowIndex]) { |
|
|
|
|
// Look from current row onwards
|
|
|
|
|
let offset = rowIndex + 1; |
|
|
|
|
// More than one row can be merged into current row
|
|
|
|
|
while (offset < flattenedRows.length) { |
|
|
|
|
// Find next row that could be merged
|
|
|
|
|
const match = _.findIndex(flattenedRows, otherRow => areRowsMatching(columnsUnion, row, otherRow), offset); |
|
|
|
|
if (match > -1) { |
|
|
|
|
const matchedRow = flattenedRows[match]; |
|
|
|
|
// Merge values from match into current row if there is a gap in the current row
|
|
|
|
|
for (let columnIndex = 0; columnIndex < columnsUnion.length; columnIndex++) { |
|
|
|
|
if (row[columnIndex] === undefined && matchedRow[columnIndex] !== undefined) { |
|
|
|
|
row[columnIndex] = matchedRow[columnIndex]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Don't visit this row again
|
|
|
|
|
mergedRows[match] = matchedRow; |
|
|
|
|
// Keep looking for more rows to merge
|
|
|
|
|
offset = match + 1; |
|
|
|
|
} else { |
|
|
|
|
// No match found, stop looking
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
// Don't visit this row again
|
|
|
|
|
mergedRows[match] = matchedRow; |
|
|
|
|
// Keep looking for more rows to merge
|
|
|
|
|
offset = match + 1; |
|
|
|
|
} else { |
|
|
|
|
// No match found, stop looking
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
acc.push(row); |
|
|
|
|
} |
|
|
|
|
acc.push(row); |
|
|
|
|
} |
|
|
|
|
return acc; |
|
|
|
|
}, []); |
|
|
|
|
return acc; |
|
|
|
|
}, |
|
|
|
|
[] as MutableColumn[][] |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
model.columns = columnsUnion; |
|
|
|
|
model.rows = compactedRows; |
|
|
|
|