Commit edb2dcf1 by David Kaltschmidt

Extracted row matching function and added comments

parent 8d70f133
...@@ -145,8 +145,8 @@ transformers['table'] = { ...@@ -145,8 +145,8 @@ transformers['table'] = {
const columnNames = {}; const columnNames = {};
// Union of all columns // Union of all columns
const columns = data.reduce((acc, d, i) => { const columns = data.reduce((acc, series) => {
d.columns.forEach((col, j) => { series.columns.forEach(col => {
const { text } = col; const { text } = col;
if (columnNames[text] === undefined) { if (columnNames[text] === undefined) {
columnNames[text] = acc.length; columnNames[text] = acc.length;
...@@ -175,76 +175,84 @@ transformers['table'] = { ...@@ -175,76 +175,84 @@ transformers['table'] = {
return; return;
} }
// Track column indexes: name -> index // Track column indexes of union: name -> index
const columnNames = {}; const columnNames = {};
const columnIndexes = [];
// Union of all non-value columns // Union of all non-value columns
const columns = data.reduce((acc, d, i) => { const columnsUnion = data.reduce((acc, series) => {
const indexes = []; series.columns.forEach(col => {
d.columns.forEach((col, j) => {
const { text } = col; const { text } = col;
if (columnNames[text] === undefined) { if (columnNames[text] === undefined) {
columnNames[text] = acc.length; columnNames[text] = acc.length;
acc.push(col); acc.push(col);
} }
indexes[j] = columnNames[text];
}); });
columnIndexes.push(indexes);
return acc; return acc;
}, []); }, []);
model.columns = columns; // Map old column index to union index per series, e.g.,
// given columnNames {A: 0, B: 1} and
// Adjust rows to new column indexes // data [{columns: [{ text: 'A' }]}, {columns: [{ text: 'B' }]}] => [[0], [1]]
let rows = data.reduce((acc, d, i) => { const columnIndexMapper = data.map(series =>
const indexes = columnIndexes[i]; series.columns.map(col => columnNames[col.text])
d.rows.forEach((r, j) => { );
// Flatten rows of all series and adjust new column indexes
const flattenedRows = data.reduce((acc, series, seriesIndex) => {
const mapper = columnIndexMapper[seriesIndex];
series.rows.forEach(row => {
const alteredRow = []; const alteredRow = [];
indexes.forEach((to, from) => { // Shifting entries according to index mapper
alteredRow[to] = r[from]; mapper.forEach((to, from) => {
alteredRow[to] = row[from];
}); });
acc.push(alteredRow); acc.push(alteredRow);
}); });
return acc; return acc;
}, []); }, []);
// Merge rows that have same values for columns // Returns true if both rows have matching non-empty fields as well as matching
const mergedRows = {}; // indexes where one field is empty and the other is not
rows = rows.reduce((acc, row, rowIndex) => { function areRowsMatching(columns, row, otherRow) {
if (!mergedRows[rowIndex]) {
let offset = rowIndex + 1;
while (offset < rows.length) {
// Find next row that has the same field values unless the respective field is undefined
const match = _.findIndex(rows, (otherRow) => {
let fieldsAreTheSame = true;
let foundFieldToMatch = false; let foundFieldToMatch = false;
for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) { for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
if (row[columnIndex] !== undefined && otherRow[columnIndex] !== undefined) { if (row[columnIndex] !== undefined && otherRow[columnIndex] !== undefined) {
if (row[columnIndex] !== otherRow[columnIndex]) { if (row[columnIndex] !== otherRow[columnIndex]) {
fieldsAreTheSame = false; return false;
} }
} else if (row[columnIndex] === undefined || otherRow[columnIndex] === undefined) { } else if (row[columnIndex] === undefined || otherRow[columnIndex] === undefined) {
foundFieldToMatch = true; foundFieldToMatch = true;
} }
if (!fieldsAreTheSame) {
break;
} }
return foundFieldToMatch;
} }
return fieldsAreTheSame && foundFieldToMatch;
}, offset); // Merge rows that have same values for columns
const mergedRows = {};
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) { if (match > -1) {
const matchedRow = rows[match]; const matchedRow = flattenedRows[match];
// Merge values into current row // Merge values from match into current row if there is a gap in the current row
for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) { for (let columnIndex = 0; columnIndex < columnsUnion.length; columnIndex++) {
if (row[columnIndex] === undefined && matchedRow[columnIndex] !== undefined) { if (row[columnIndex] === undefined && matchedRow[columnIndex] !== undefined) {
row[columnIndex] = matchedRow[columnIndex]; row[columnIndex] = matchedRow[columnIndex];
} }
} }
// Dont visit this row again
mergedRows[match] = matchedRow; mergedRows[match] = matchedRow;
// Keep looking for more rows to merge // Keep looking for more rows to merge
offset = match + 1; offset = match + 1;
} else { } else {
// No match found, stop looking
break; break;
} }
} }
...@@ -253,7 +261,8 @@ transformers['table'] = { ...@@ -253,7 +261,8 @@ transformers['table'] = {
return acc; return acc;
}, []); }, []);
model.rows = rows; model.columns = columnsUnion;
model.rows = compactedRows;
} }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment