繁体   English   中英

从 typescript 中的对象列表中查找键的唯一值的高效方法

[英]Performant way of finding unique values of keys from a list of objects in typescript

在此处输入图像描述

我正在开发一个 angular 应用程序,它有一个

  1. 一组过滤器
  2. 和表格中的记录

表中的列对应于过滤器。 在任何时候,过滤器都包含来自相应列的唯一值作为选项。

对于一条记录,一列可以包含多个值(即来自相应过滤器的多个选项)

当用户从过滤器中选择一个选项时,表中的记录将被过滤,并且过滤后的结果(根据用户的选择)显示给用户。

导出过滤记录集后,通过查找每列的唯一值,从过滤记录集导出每个过滤器的唯一值。

过滤器对象的键对应于记录对象的列我有一个记录列表和一个过滤器列表。 我想遍历这两个列表并找到每个键的列的唯一值。

我正在使用以下逻辑从我的消息中查找过滤器的唯一选项。

export function filterOptionsService(records: Record[], filters: RecordFilter[]): RecordFilter[] {
    const newFilters: RecordFilter[] = filters.map(filter => {

        //logic to find all values for a column from the set of records 
        const filterOptions = records.reduce((uniqueList, record) => uniqueList.concat(record[filter.key]), []);

        //logic to find unique values for a column from the set of records
        //which act as options of corresponding filters.
        const uniqueOptions = uniqBy(filterOptions, (opt) => filter.valueFunction ? filter.valueFunction(opt) : opt);

        const filterOptions: FilterOption[] = uniqueOptions.map(value => {
            return {
                label: filter.labelFunction ? filter.labelFunction(value) : value,
                value: filter.valueFunction ? filter.valueFunction(value) : value,
            };
        });
        filter.options = orderBy(dropListOptions, 'label');

        //here is my logic to find the count of each option, present in the filtered records
        filter.options = filter.options.map(option => ({
            ...option,
            count: filter.valueFunction
                ? filterOptions.filter(value => filter.valueFunction(value) === option.value).length
                : filterOptions.filter(value => value === option.value).length
        }));
        return filter;
    });
    return newFilters;
}

interface Filter {
    key: string;
    labelFunction?: Function;
    valueFunction?: Function;
    order: number;
    multiple: boolean;
    options: DropListOption[];
    values: DropListOption[];
}


interface Record {
    column1: string;
    column2: string;
    column3: string | string[];
    .
    .
    columnN: string;
}

下面的逻辑在我的代码中花费的时间最多。 8k 条记录大约需要 7 秒。

const filterOptions = records.reduce((uniqueList, record) => 
                              uniqueList.concat(record[filter.key]), []); 

我无法让我的代码表现得更好。 请你能建议我哪里出错了。

Here is sample code on typescrip playground https://www.typescriptlang.org/play?#code/FASwdgLgpgTgZgQwMZQAQDEQBtowPIAOEIA9mKgN7Co201YIBGUWAXKgM4QzgDmA3NTq0AbgiwBXKOwRgAnoOG1kxEVAD87RiRJYosxUtQEEcrCQQATTalkKhSpCQmQbYCQFtmMQzQC+-LTA1AD0IRwIHgR6qGJ6HKhwJDCoANZQcrYwaAQwJASwEHIAjAA0xnkFMEUATKigkLCIKKgASlBOMJaYOLCUDsLpcuxcPGAC9UaoDMxY6C5IxGQ282CLpGC+wnFSq+vL7HtLmwN0yZaw7O5esFt0HhI4INHSqNq6+idT+ccch9i4QjHADaAF07qJxFI-hgAbAgRswVsAkFgGEKvlqiAoAkSHA2h1zqgkAwOAkENlOJE0AgEkNUHiCZ1unCUiTaRw0SFUBAABYgBICzggKJYEBwbGWVDZKo4yAIY6oDyZFQScTE0kJXm0pV2JXJHKVQrYzngXDNNCtEgAd36dFy+UKJRG3D4SIGDqqtRdYwEwACwWATjAXFQ4BAxHEVutMOjYNQAF5UMDTlNhBRPU7iqxgQAiMhQXPlXN87KF0GlTPVOQ1Vi5phIXN+UqptO0DNG6vZvMStRF1C5sDgcuVzve3MXOBNlttqYdx1dnP5sCF4ulqCrge9zeD4e5itV8cNputtPg4JBMIASVsHgZYCwKrJIF4Q-GsShOJ5JDSGQxXsyJIUg4EVonFEAkAVDYgzIUNw0jOZWVjQkuh6XB4yTFNZyUCghjrQ8Sn7c5LjKJVHmIF5WEQLAOCgcofg2P4wXKHYcXYMFm1PNNcIyfCxxrIiukuGpygeJ5KOo2j6KIRicwrD9JDY5NQT8GguKMc9gglXp8Bk2CAGVYBECCoAACngkAoxtDhSgs8Q0NgDgAE pBGCdEb21NRUGKAAWRJWQZRgACsOggTl0WtXkoHIDyEC8gAOVJpRtQKQsWBI+TQWYUuySwJBaTEICgsgeQQdIEgANgAWgAdk4QkwEsDgADpgDgBZFW0wE9JDQyYGMlBTLyGN2DjeSusc0aUJZHSwSc-pTgmmAWo8BACFMpbEwAPjtIwwnMXgIO-fzGtsLAsAU6FEmSWxiV0TxyDgPI70y+qIAZfFsmZBJT2DUMloRWDE2SmNmty-KzNMlwQAARykAAZAUIHKYb5oTHbUGhuGoERrhmuDSCICGm1gSW5qhlBJzyjmwIuN+2CPmag7TIAcgBnqOBZ0p2d+FzsNbPwXP9QMgA

我认为您遇到的性能问题是Array.prototype.concat()不会修改现有数组,而是返回一个新数组。 不变性很好,但它似乎与您的用例无关:除了最后一个之外,您创建的每个uniqueList数组都将被丢弃。 Object 在 JavaScript 中的创建速度相当快,但创建数千个数组对象只是为了立即丢弃它们会减慢速度。

我的建议是将concat()替换为修改现有数组的内容,例如Array.prototype.push()

也就是说,你可以改变

const filterOptions = rows.reduce(
  (uniqueList, row) => uniqueList.concat(row[filter.key]), []
);

const filterOptions: string[] = [];
for (let row of rows) filterOptions.push(...row[filter.key]);

当我运行一个创建 6000 行和 14 个过滤器的模拟时(请参阅下面的游乐场链接), concat()版本大约需要 7.5 秒,而push()版本大约需要 38 milliseconds 希望大约 200 的改进因素在您的环境中保持不变,并产生足够的影响以满足您的需求。

请注意,我没有处理您的原始问题似乎具有的任何“唯一”或“功能”方面,因为您的可重现示例代码也没有涉及到这一点。 通过 object 键可能比数组更容易计算唯一字符串,甚至可能通过Set 但同样,希望将concat()更改为push()对您来说就足够了。

Playground 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM