improve findInTree performance

by passing a list of paths to find in the tree up front

#154

closes #152
This commit is contained in:
Lukas Siemon 2020-02-22 11:13:56 -08:00 committed by GitHub
parent 940519b15b
commit 8cb7d807f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 41 deletions

View file

@ -1,19 +1,20 @@
'use strict' 'use strict';
const scanner = require('object-scan') const objectScan = require('object-scan');
// For all items in `tree` matching a path selector specified const findInTree = (haystack, needles) => {
// in `selector`, call `onResult` with the item, its parent and const result = Object.create(null);
// the path to the item. needles.forEach((needle) => {
// Example: result[needle] = [];
// tree: {foo: [{bar: 1}], hey: {there: [{bar: 2}]}} });
// selector: **[*].bar objectScan(needles, {
const findInTree = (tree, selector, onResult) => { filterFn: (key, value, { parents, matchedBy }) => {
scanner([selector], { matchedBy.forEach((needle) => {
filterFn: (key, value, { parents }) => { result[needle].push([value, parents]);
onResult(value, parents[0], key); });
} }
})(tree); })(haystack);
} return result;
};
module.exports = findInTree module.exports = findInTree;

View file

@ -1,11 +1,15 @@
'use strict' 'use strict'
const get = require('lodash/get')
const findInTree = require('../lib/find-in-tree') const findInTree = require('../lib/find-in-tree')
const parseCommonData = (_ctx) => { const parseCommonData = (_ctx) => {
const {profile, opt, res} = _ctx const {profile, opt, res} = _ctx
const c = res.common || {} const c = res.common || {}
const matches = findInTree(res, [
'**.oprX', '**.icoX', '**.prodX', '**.pRefL', '**.locX',
'**.ani.fLocX', '**.ani.tLocX', '**.fLocX', '**.tLocX',
'**.remX', '**.himX', '**.polyG.polyXL'
]);
const common = {} const common = {}
const ctx = {..._ctx, common} const ctx = {..._ctx, common}
@ -13,16 +17,16 @@ const parseCommonData = (_ctx) => {
common.operators = [] common.operators = []
if (Array.isArray(c.opL)) { if (Array.isArray(c.opL)) {
common.operators = c.opL.map(op => profile.parseOperator(ctx, op)) common.operators = c.opL.map(op => profile.parseOperator(ctx, op))
findInTree(res, '**.oprX', (idx, parent) => { matches['**.oprX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.operator = common.operators[idx] if ('number' === typeof idx) parents[0].operator = common.operators[idx]
}) })
} }
common.icons = [] common.icons = []
if (Array.isArray(c.icoL)) { if (Array.isArray(c.icoL)) {
common.icons = c.icoL.map(icon => profile.parseIcon(ctx, icon)) common.icons = c.icoL.map(icon => profile.parseIcon(ctx, icon))
findInTree(res, '**.icoX', (idx, parent) => { matches['**.icoX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.icon = common.icons[idx] if ('number' === typeof idx) parents[0].icon = common.icons[idx]
}) })
} }
@ -30,11 +34,11 @@ const parseCommonData = (_ctx) => {
if (Array.isArray(c.prodL)) { if (Array.isArray(c.prodL)) {
common.lines = c.prodL.map(l => profile.parseLine(ctx, l)) common.lines = c.prodL.map(l => profile.parseLine(ctx, l))
findInTree(res, '**.prodX', (idx, parent) => { matches['**.prodX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.line = common.lines[idx] if ('number' === typeof idx) parents[0].line = common.lines[idx]
}) })
findInTree(res, '**.pRefL', (idxs, parent) => { matches['**.pRefL'].forEach(([idxs, parents]) => {
parent.lines = idxs.filter(idx => !!common.lines[idx]).map(idx => common.lines[idx]) parents[0].lines = idxs.filter(idx => !!common.lines[idx]).map(idx => common.lines[idx])
}) })
// todo // todo
// **.dep.dProdX: departureLine -> common.lines[idx] // **.dep.dProdX: departureLine -> common.lines[idx]
@ -55,35 +59,35 @@ const parseCommonData = (_ctx) => {
} }
// todo: correct props? // todo: correct props?
findInTree(res, '**.locX', (idx, parent) => { matches['**.locX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.location = common.locations[idx] if ('number' === typeof idx) parents[0].location = common.locations[idx]
}) })
findInTree(res, '**.ani.fLocX', (idxs, parent) => { matches['**.ani.fLocX'].forEach(([idxs, parents]) => {
parent.fromLocations = idxs.map(idx => common.locations[idx]) parents[0].fromLocations = idxs.map(idx => common.locations[idx])
}) })
findInTree(res, '**.ani.tLocX', (idxs, parent) => { matches['**.ani.tLocX'].forEach(([idxs, parents]) => {
parent.toLocations = idxs.map(idx => common.locations[idx]) parents[0].toLocations = idxs.map(idx => common.locations[idx])
}) })
findInTree(res, '**.fLocX', (idx, parent) => { matches['**.fLocX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.fromLocation = common.locations[idx] if ('number' === typeof idx) parents[0].fromLocation = common.locations[idx]
}) })
findInTree(res, '**.tLocX', (idx, parent) => { matches['**.tLocX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.toLocation = common.locations[idx] if ('number' === typeof idx) parents[0].toLocation = common.locations[idx]
}) })
} }
common.hints = [] common.hints = []
if (opt.remarks && Array.isArray(c.remL)) { if (opt.remarks && Array.isArray(c.remL)) {
common.hints = c.remL.map(hint => profile.parseHint(ctx, hint)) common.hints = c.remL.map(hint => profile.parseHint(ctx, hint))
findInTree(res, '**.remX', (idx, parent) => { matches['**.remX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.hint = common.hints[idx] if ('number' === typeof idx) parents[0].hint = common.hints[idx]
}) })
} }
common.warnings = [] common.warnings = []
if (opt.remarks && Array.isArray(c.himL)) { if (opt.remarks && Array.isArray(c.himL)) {
common.warnings = c.himL.map(w => profile.parseWarning(ctx, w)) common.warnings = c.himL.map(w => profile.parseWarning(ctx, w))
findInTree(res, '**.himX', (idx, parent) => { matches['**.himX'].forEach(([idx, parents]) => {
if ('number' === typeof idx) parent.warning = common.warnings[idx] if ('number' === typeof idx) parents[0].warning = common.warnings[idx]
}) })
} }
@ -92,10 +96,9 @@ const parseCommonData = (_ctx) => {
common.polylines = c.polyL.map(p => profile.parsePolyline(ctx, p)) common.polylines = c.polyL.map(p => profile.parsePolyline(ctx, p))
// todo: **.ani.poly -> parsePolyline() // todo: **.ani.poly -> parsePolyline()
findInTree(res, '**.polyG.polyXL', (idxs, _, path) => { matches['**.polyG.polyXL'].forEach(([idxs, parents]) => {
const idx = idxs.find(idx => !!common.polylines[idx]) // find any given polyline const idx = idxs.find(idx => !!common.polylines[idx]) // find any given polyline
const jny = get(res, path.slice(0, -2)) parents[1].polyline = common.polylines[idx]
jny.polyline = common.polylines[idx]
}) })
} }