具有多个对象和多个过滤器的过滤器阵列



我有一个需要过滤的数组,它由许多对象组成,使用循环,它很有效,但确实会减慢我的应用程序的速度,我会简化我的数组。

let arrayToFilter = [{id:1,month:'Dec'},{id:2,month:'Nov'},{id:3,month:'Feb'},{id:4,month:'Nov'},{id:5,month:'Jan'}]
let filter = ['Dec','Nov']

不循环(对于var i=0…..(如何只显示具有月份Dec&十一月或者使用过滤器。来自JavaScript?我需要它快速(而不是减慢我的应用程序(、高效和有效。

之前谢谢

如果您有定义良好的条件,您可以尝试对要筛选的键预计算索引。最初,它将花费与执行单个过滤器操作相同的时间,但之后将是即时的。

const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const bench = (tag, fn) => {
const now = performance.now();
fn();
console.log(`${tag} executed in ${performance.now() - now}ms`);
};
// this is just to create a ton of elements.
const data = Array.from({ length: 1000000 }, (_, i) => {
return { id: i, month: MONTHS[Math.random() * 12 | 0]};
});
const index = new Map();
for (datum of data) {
const bucket = index.get(datum.month);

if (bucket == null) {
index.set(datum.month, [datum]);
} else {
bucket.push(datum);
}
}
bench('filter [Dec, Nov]', () => {
['Dec', 'Nov'].reduce((r, f) => r.concat(index.get(f)), []);
});

bench('filter [Nov, Feb, May]', () => {
['Nov', 'Feb', 'May'].reduce((r, f) => r.concat(index.get(f)), []);
});

bench('filter [Apr, Dec, Feb, Jan, Jul]', () => {
['Apr', 'Dec', 'Feb', 'Jan', 'Jul'].reduce((r, f) => r.concat(index.get(f)), []);
});

在我的PC/Browser上,根据过滤器的复杂性,我在大约0.3ms-2ms内过滤1M条记录。这是在一帧内(每秒60帧(。

如果你愿意,你可以创建一个函数,为你生成一个索引,你可以用来过滤

const createIndexOn = (date, selector) => {
const index = new Map();
for (datum of data) {
const bucket = index.get(datum.month);

if (bucket == null) {
index.set(datum.month, [datum]);
} else {
bucket.push(datum);
} 
}
return index;
};
const monthIndex = createIndexOn(data, (d) => d.month);

如果你需要做一些类似于复合过滤器的事情,比如说monthname,你可以在month上创建一个索引,按month过滤结果,根据name上的结果创建一个指数,并按名称过滤。您也可以创建2个离散索引,只需取一个交集。不管怎样,它都很快。

这一切都是基于您对代码进行了分析,并知道在6000*|Filters|上循环很慢(老实说,在达到100k之前可能还不错(。问题可能出在其他地方。例如,如果您正在使用react,并且每次组件更改时都要进行筛选,则应该记录结果或使用其他性能调整工具。

由于O(1)的时间复杂性,我将使用Set作为过滤器

例如

// Generate random sample data
const length = 6000
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
const arrayToFilter = Array.from({ length }, (_, i) => ({
id: i + 1,
month: months[Math.floor(Math.random() * months.length)]
}))
const filter = ['Dec','Nov'] // whatever you've actually got
const hashset = new Set(filter)
const t1 = performance.now()
// Filter the array
const filtered = arrayToFilter.filter(({ month }) => hashset.has(month))
const t2 = performance.now()
console.log(`Operation took ${t2 - t1}ms`)
console.info(`${filtered.length} results`, filtered)
.as-console-wrapper { max-height: 100% !important; }

最新更新