@samitouri / QOS-React-2 / commits / 1efb14bcf6

Rewrite mergeKeySets to be O(n) instead of O(n^3)

Ben Alpert committed Jan 10, 2014 at 15:31 UTC 1efb14bcf6a5702febefdce5bcd34c70a44d5fce
1 file changed +23 -26
src/addons/transitions/ReactTransitionKeySet.js
+23 -26
@@ -21,8 +21,6 @@
21
22 var ReactChildren = require('ReactChildren');
23
24 -var MERGE_KEY_SETS_TAIL_SENTINEL = {};
25 -
24 var ReactTransitionKeySet = {
25 /**
26 * Given `this.props.children`, return an object mapping key to child. Just
@@ -71,37 +69,36 @@ var ReactTransitionKeySet = {
69 prev = prev || {};
70 next = next || {};
71
74 - var keySet = {};
75 - var prevKeys = Object.keys(prev).concat([MERGE_KEY_SETS_TAIL_SENTINEL]);
76 - var nextKeys = Object.keys(next).concat([MERGE_KEY_SETS_TAIL_SENTINEL]);
77 - var i;
78 - for (i = 0; i < prevKeys.length - 1; i++) {
79 - var prevKey = prevKeys[i];
72 + // For each key of `next`, the list of keys to insert before that key in
73 + // the combined list
74 + var nextKeysPending = {};
75 +
76 + var pendingKeys = [];
77 + for (var prevKey in prev) {
78 if (next[prevKey]) {
81 - continue;
79 + if (pendingKeys.length) {
80 + nextKeysPending[prevKey] = pendingKeys;
81 + pendingKeys = [];
82 + }
83 + } else {
84 + pendingKeys.push(prevKey);
85 }
86 + }
87
84 - // This key is not in the new set. Place it in our
85 - // best guess where it should go. We do this by searching
86 - // for a key after the current one in prevKeys that is
87 - // still in nextKeys, and inserting right before it.
88 - // I know this is O(n^2), but this is not a particularly
89 - // hot code path.
90 - var insertPos = -1;
91 -
92 - for (var j = i + 1; j < prevKeys.length; j++) {
93 - insertPos = nextKeys.indexOf(prevKeys[j]);
94 - if (insertPos >= 0) {
95 - break;
88 + var i;
89 + var keySet = {};
90 + for (var nextKey in next) {
91 + if (nextKeysPending[nextKey]) {
92 + for (i = 0; i < nextKeysPending[nextKey].length; i++) {
93 + keySet[nextKeysPending[nextKey][i]] = true;
94 }
95 }
98 -
99 - // Insert before insertPos
100 - nextKeys.splice(insertPos, 0, prevKey);
96 + keySet[nextKey] = true;
97 }
98
103 - for (i = 0; i < nextKeys.length - 1; i++) {
104 - keySet[nextKeys[i]] = true;
99 + // Finally, add the keys which didn't appear before any key in `next`
100 + for (i = 0; i < pendingKeys.length; i++) {
101 + keySet[pendingKeys[i]] = true;
102 }
103
104 return keySet;