Add `MapUtil.pushValue` for maps of arrays (#805)

With some frequency we find ourselves needing to maintain maps whose
values are arrays that we append to. `MapUtil.pushValue` is a utility
method for these cases.

Existing usage in `aggregate.js` has been modified to use the new
function.

Test plan: Unit tests included.
This commit is contained in:
Dandelion Mané 2018-09-11 15:26:54 -07:00 committed by GitHub
parent 4b0693e2a7
commit bf1e85d6f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 10 deletions

View File

@ -2,6 +2,7 @@
import sortBy from "lodash.sortby"; import sortBy from "lodash.sortby";
import stringify from "json-stable-stringify"; import stringify from "json-stable-stringify";
import * as MapUtil from "../../../util/map";
import {NodeTrie, EdgeTrie} from "../../../core/trie"; import {NodeTrie, EdgeTrie} from "../../../core/trie";
import type {NodeType, EdgeType} from "../../adapters/pluginAdapter"; import type {NodeType, EdgeType} from "../../adapters/pluginAdapter";
import type {ScoredConnection} from "../../../core/attribution/pagerankNodeDecomposition"; import type {ScoredConnection} from "../../../core/attribution/pagerankNodeDecomposition";
@ -53,11 +54,7 @@ export function aggregateByNodeType(
const nodeTypeToConnections = new Map(); const nodeTypeToConnections = new Map();
for (const x of xs) { for (const x of xs) {
const type = typeTrie.getLast(x.source); const type = typeTrie.getLast(x.source);
const connections = nodeTypeToConnections.get(type) || []; MapUtil.pushValue(nodeTypeToConnections, type, x);
if (connections.length === 0) {
nodeTypeToConnections.set(type, connections);
}
connections.push(x);
} }
const aggregations: NodeAggregation[] = []; const aggregations: NodeAggregation[] = [];
for (const [ for (const [
@ -109,11 +106,7 @@ export function aggregateByConnectionType(
} }
const edge = x.connection.adjacency.edge; const edge = x.connection.adjacency.edge;
const type = typeTrie.getLast(edge.address); const type = typeTrie.getLast(edge.address);
const connections = relevantMap.get(type) || []; MapUtil.pushValue(relevantMap, type, x);
if (connections.length === 0) {
relevantMap.set(type, connections);
}
connections.push(x);
} }
function createAggregation( function createAggregation(

View File

@ -146,3 +146,19 @@ export function merge<K, V>(
} }
return result; return result;
} }
/**
* Given a map whose values are arrays, push an element onto the array
* corresponding to the given key. If the key is not in the map, first
* insert it with value a new empty array.
*
* If the key is already in the map, its value will be mutated, not
* replaced.
*/
export function pushValue<K, V>(map: Map<K, V[]>, key: K, value: V): void {
let arr = map.get(key);
if (arr == null) {
map.set(key, (arr = []));
}
arr.push(value);
}

View File

@ -294,4 +294,27 @@ describe("util/map", () => {
]); ]);
}); });
}); });
describe("pushValue", () => {
it("works when the map has no matching key", () => {
const map = new Map();
MapUtil.pushValue(map, "foo", 3);
expect(map).toEqual(new Map().set("foo", [3]));
});
it("works when the map has a matching key", () => {
const map = new Map().set("foo", [3]);
MapUtil.pushValue(map, "foo", 4);
expect(map).toEqual(new Map().set("foo", [3, 4]));
});
it("works when the map already has an empty array", () => {
const map = new Map().set("foo", []);
MapUtil.pushValue(map, "foo", 1);
expect(map).toEqual(new Map().set("foo", [1]));
});
it("preserves array identity", () => {
const arr = [];
const map = new Map().set("foo", arr);
MapUtil.pushValue(map, "foo", 1);
expect(map.get("foo")).toBe(arr);
});
});
}); });