提交 4c83c567 编写于 作者: C chrmarti 提交者: GitHub

#55: Improve result sorting performance (#9602)

上级 2cc6141e
......@@ -79,6 +79,29 @@ export function findFirst<T>(array: T[], p: (x: T) => boolean): number {
return low;
}
/**
* Returns the top N elements from the array.
*
* Faster than sorting the entire array when the array is a lot larger than N.
*
* @param array The unsorted array.
* @param compare A sort function for the elements.
* @param n The number of elements to return.
* @return The first n elemnts from array when sorted with compare.
*/
export function top<T>(array: T[], compare: (a: T, b: T) => number, n: number) {
const result = array.slice(0, n).sort(compare);
for (let i = n, m = array.length; i < m; i++) {
const element = array[i];
if (compare(element, result[n - 1]) < 0) {
result.pop();
const j = findFirst(result, e => compare(element, e) < 0);
result.splice(j, 0, element);
}
}
return result;
}
export function merge<T>(arrays: T[][], hashFn?: (element: T) => string): T[] {
const result = new Array<T>();
if (!hashFn) {
......
......@@ -57,8 +57,8 @@ export function compareByPrefix(one: string, other: string, lookFor: string): nu
let elementBName = other.toLowerCase();
// Sort prefix matches over non prefix matches
let elementAPrefixMatch = elementAName.indexOf(lookFor) === 0;
let elementBPrefixMatch = elementBName.indexOf(lookFor) === 0;
let elementAPrefixMatch = strings.startsWith(elementAName, lookFor);
let elementBPrefixMatch = strings.startsWith(elementBName, lookFor);
if (elementAPrefixMatch !== elementBPrefixMatch) {
return elementAPrefixMatch ? -1 : 1;
}
......
......@@ -60,5 +60,17 @@ suite('Arrays', () => {
assert.deepEqual(arrays.distinct(['32', 'constructor', 'proto', 'proto', 'constructor'], compare), ['32', 'constructor', 'proto']);
assert.deepEqual(arrays.distinct(['32', '4', '5', '32', '4', '5', '32', '4', '5', '5'], compare), ['32', '4', '5']);
});
test('top', function () {
const cmp = (a, b) => a - b;
assert.deepEqual(arrays.top([], cmp, 1), []);
assert.deepEqual(arrays.top([1], cmp, 0), []);
assert.deepEqual(arrays.top([1, 2], cmp, 1), [1]);
assert.deepEqual(arrays.top([2, 1], cmp, 1), [1]);
assert.deepEqual(arrays.top([1, 3, 2], cmp, 2), [1, 2]);
assert.deepEqual(arrays.top([3, 2, 1], cmp, 3), [1, 2, 3]);
assert.deepEqual(arrays.top([4, 6, 2, 7, 8, 3, 5, 1], cmp, 3), [1, 2, 3]);
});
});
......@@ -5,6 +5,7 @@
'use strict';
import * as arrays from 'vs/base/common/arrays';
import {TPromise} from 'vs/base/common/winjs.base';
import nls = require('vs/nls');
import {ThrottledDelayer} from 'vs/base/common/async';
......@@ -182,27 +183,19 @@ export class OpenAnythingHandler extends QuickOpenHandler {
// Combine symbol results and file results
let result = [...results[0].entries, ...results[1].entries];
// Sort
const normalizedSearchValue = strings.stripWildcards(searchValue).toLowerCase();
result.sort((elementA, elementB) => QuickOpenEntry.compareByScore(elementA, elementB, searchValue, normalizedSearchValue, this.scorerCache));
const sortedResultTime = Date.now();
// Apply Range
result.forEach((element) => {
if (element instanceof FileEntry) {
(<FileEntry>element).setRange(searchWithRange ? searchWithRange.range : null);
}
});
// Cache for fast lookup
this.resultsToSearchCache[searchValue] = result;
// Cap the number of results to make the view snappy
const viewResults = result.length > OpenAnythingHandler.MAX_DISPLAYED_RESULTS ? result.slice(0, OpenAnythingHandler.MAX_DISPLAYED_RESULTS) : result;
// Sort
const normalizedSearchValue = strings.stripWildcards(searchValue).toLowerCase();
const compare = (elementA, elementB) => QuickOpenEntry.compareByScore(elementA, elementB, searchValue, normalizedSearchValue, this.scorerCache);
const viewResults = arrays.top(result, compare, OpenAnythingHandler.MAX_DISPLAYED_RESULTS);
const sortedResultTime = Date.now();
// Apply highlights to file entries
// Apply range and highlights to file entries
viewResults.forEach(entry => {
if (entry instanceof FileEntry) {
entry.setRange(searchWithRange ? searchWithRange.range : null);
const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, true /* fuzzy highlight */);
entry.setHighlights(labelHighlights, descriptionHighlights);
}
......@@ -324,21 +317,15 @@ export class OpenAnythingHandler extends QuickOpenHandler {
const unsortedResultTime = Date.now();
// Sort
results.sort((elementA, elementB) => QuickOpenEntry.compareByScore(elementA, elementB, searchValue, normalizedSearchValueLowercase, this.scorerCache));
const compare = (elementA, elementB) => QuickOpenEntry.compareByScore(elementA, elementB, searchValue, normalizedSearchValueLowercase, this.scorerCache);
const viewResults = arrays.top(results, compare, OpenAnythingHandler.MAX_DISPLAYED_RESULTS);
const sortedResultTime = Date.now();
// Apply Range
results.forEach((element) => {
if (element instanceof FileEntry) {
(<FileEntry>element).setRange(range);
}
});
// Cap the number of results to make the view snappy
const viewResults = results.length > OpenAnythingHandler.MAX_DISPLAYED_RESULTS ? results.slice(0, OpenAnythingHandler.MAX_DISPLAYED_RESULTS) : results;
// Apply highlights
// Apply range and highlights
viewResults.forEach(entry => {
if (entry instanceof FileEntry) {
entry.setRange(range);
}
const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, true /* fuzzy highlight */);
entry.setHighlights(labelHighlights, descriptionHighlights);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册