Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 关于复杂性和交集的复杂挑战_Javascript_Math_Time Complexity_Computer Science_Complexity Theory - Fatal编程技术网

Javascript 关于复杂性和交集的复杂挑战

Javascript 关于复杂性和交集的复杂挑战,javascript,math,time-complexity,computer-science,complexity-theory,Javascript,Math,Time Complexity,Computer Science,Complexity Theory,前言 注意:这个问题是关于复杂性的。我在这里使用了一个复杂的设计模式,你不需要为了理解这个问题而去理解它。我本可以简化它,但为了防止出错,我选择保持它相对不变。代码是用TypeScript编写的,这是一组超JavaScript 代码 考虑以下类别: export class ConcreteFilter implements Filter { interpret() { // rows is a very large array return (rows

前言

注意:这个问题是关于复杂性的。我在这里使用了一个复杂的设计模式,你不需要为了理解这个问题而去理解它。我本可以简化它,但为了防止出错,我选择保持它相对不变。代码是用TypeScript编写的,这是一组超JavaScript


代码

考虑以下类别:

export class ConcreteFilter implements Filter {
    interpret() {
        // rows is a very large array
        return (rows: ReportRow[], filterColumn: string) => {
            return rows.filter(row => {
                // I've hidden the implementation for simplicity, 
                // but it usually returns either an empty array or a very short one.
                }
            }).map(row => <string>row[filterColumn]);
        }
    }
}
它接收一个过滤器数组,并返回过滤器返回的所有“filterColumn”的不同数组

在for循环中,我从每个过滤器中获得结果(字符串数组),然后进行交集操作


问题

报表行数组很大,因此每个
runFilter
操作都很昂贵(另一方面,过滤器数组很短)。我希望尽可能少地迭代报表行数组。此外,
runFilter
操作很可能返回零结果或很少结果


解释

假设我有3个过滤器和10亿个报告行。内部迭代,即
ConcreteFilter
中的迭代,将发生30亿次,即使
runFilter
的第一次执行返回0个结果,因此我有20亿次冗余迭代

例如,我可以在每次迭代开始时检查
intersectionResults
是否为空,如果为空,则中断循环。但我相信在数学上有更好的解决方案

另外,如果第一个
runFIlter
exectuion返回15个结果,我希望下一个exectuion只接收15个报告行的数组,这意味着我希望交集操作影响下一次调用
runFIlter
的输入

我可以在每次迭代后修改报表行数组,但我看不出如何以一种不会比现在更昂贵的有效方式进行修改

一个好的解决方案是删除
map
操作,然后在每个操作中传递已经过滤的数组,而不是整个数组,但我不允许这样做,因为我不能更改过滤器接口的结果格式


我的问题

我想得到你能想到的最好的解决方案以及一个解释


提前非常感谢每一位愿意花时间帮助我的人。

不确定这会有多有效,但这里有一种可能的方法,你可以采取。如果按筛选列对行进行预处理,则可以检索匹配的行。如果您通常有两个以上的过滤器,那么这种方法可能更有益,但是它会占用更多内存。您可以根据过滤器的数量对方法进行分支。可能有一些TS构造更有用,但不太熟悉。以下代码中有一些注释:

var map = {};

// Loop over every row, keep a map of rows with a particular filter value.
allRows.forEach(row => {
    const v = row[filterColumn];
    let items;
    items = map[v] = map[v] || [];
    items.push(row)
});

let rows = allRows;
filters.forEach(f => {
    // Run the filter and return the unique set of matched strings
    const matches = unique(f.execute(rows, filterColumn));
    // For each of the matched strings, go and look up the remaining rows and concat them for the next filter.
    rows = [].concat(...matches.reduce(m => map[v]));
});

// Loop over the rows that made it all the way through, extract the value and then unique() the collection
return unique(rows.map(row => row[filterColumn]));
再考虑一下,您可以使用类似的方法,但只需按每个过滤器进行操作:

let rows = allRows;
filters.forEach(f => {
    const matches = f.execute(rows, filterColumn);
    let map = {};
    matches.forEach(m => {
        map[m] = true;
    });

    rows = rows.filter(row => !!map[row[filterColumn]]);
});
return distinctify(rows.map(row => row[filterColumn]));

如果
runFilter
花费的时间最多,那么首先要尝试的是用for循环替换
foo.filter().map()
调用。如果所有内容都与筛选器匹配,则将数组循环两次。结果的顺序重要吗?@Evantimboli我可以合并过滤器和贴图,但有什么区别?两者都是O(n)。无论如何,关键在于解释和功能。这就是我真正能够发挥作用的地方。这是一个顺序问题——SQL中众所周知的行为。您应该首先执行减小集合大小的操作。它最大限度地减少了第二次操作所做的工作。两者都可能是O(n),但对于第二个操作,您可以通过一个序列而不是另一个序列来减少n的大小。@duffymo这正是我所做的。如您所见,过滤器位于贴图之前,因此顺序正确。不管怎样,我的问题是关于改进解释器和函数,而不是ColumnValueFilter类。@duffymo我对我的问题进行了编辑,使其更加简短和中肯。我通常有一到三个过滤器,但有时更多。只有两个过滤器是很常见的。我喜欢你的答案,我投了赞成票,但我只会接受一个答案,要么即使只有两个过滤器也能提高效率,要么证明(数学上或以不同的方式)不可能有更好的答案。我不确定你所说的“证明不可能有更好的答案”是什么意思。以什么方式证明?
let rows = allRows;
filters.forEach(f => {
    const matches = f.execute(rows, filterColumn);
    let map = {};
    matches.forEach(m => {
        map[m] = true;
    });

    rows = rows.filter(row => !!map[row[filterColumn]]);
});
return distinctify(rows.map(row => row[filterColumn]));