如何重构我的代码以减少嵌套循环的数量?
How do I refactor my code to reduce the amount of nested loops?
这是一个辅助函数,它可以将类似对象的数组转换为实际数组,然后遍历可迭代对象,将列表中的每个值提供给回调函数:
var each = function(iterable, callback) {
iterable = Array.prototype.concat.apply([], iterable);
for(var i = 0; i < iterable.length; i++) {
callback.apply(iterable[i], [iterable[i], i]);
}
return iterable;
};
这里我使用前面提到的辅助函数来遍历数组:
var found = [];
each(arguments, function(argument) {
each(argument.split(","), function(selector) {
each(handle(selector), function(element) {
if(found.indexOf(element) < 0) {
found.push(element);
}
});
});
});
第一个循环遍历参数。第二个循环拆分选择器,第三个循环遍历请求的元素并将它们添加到 found
数组(如果尚未添加)。
注意:handle
函数采用选择器(字符串)和 returns 使用 document.querySelectorAll
的元素列表。
此脚本有效,但问题是可读性和性能。
当有许多参数包含多个(~5-10)逗号分隔的选择器,然后由 handle
函数单独处理时,会出现性能问题。
我使用 类 而不是 id 解决了这个问题。
然后是可读性问题,我试图通过将第二个循环移到父循环之外来解决这个问题,但这需要创建更多变量,唯一的区别是改变了 where each
循环,这使得可读性更差,因为要阅读的代码更多。
问题:如何重构我的代码以减少嵌套循环的数量?
还有,第一个循环有必要吗?如果我不使用它,我将如何遍历参数以拆分它们以获得每个单独的选择器?我知道 split
方法适用于 String
类型,不能在数组上调用。
注意:我使用的是 vanilla JavaScript,不包括任何库、框架或外部脚本。
您似乎希望收集一些出现在某些顺序数据源中的值,例如
["A,B", "C,A,D", "A", "C,E,B"]
到集合(没有重复项)如
{"A", "B", "C", "D", "E"}
您可以在没有任何第三方库的情况下使用三个嵌套循环来做到这一点(无需担心性能 或 可读性):
const s = new Set();
for (let x of arguments) {
for (let g of x.split(",")) {
for (let i of g) {
s.add(i);
}
}
}
按功能编写,您可以将整个事情减少到:
new Set(arguments.join().split(','))
这当然假设您的任何选择器中都没有逗号。
这里的列表并不是真正的嵌套,因为您分三步完全处理了原始列表。细分:
- 原文:
[ 'A,B', 'C,A,D', 'A', 'C,E,B' ]
- 加入后:
'A,B,C,A,D,A,C,E,B'
- 拆分后:
[ 'A', 'B', 'C', 'A', 'D', 'A', 'C', 'E', 'B' ]
- 设置后:
Set { 'A', 'B', 'C', 'D', 'E' }
我认为即使在循环情况下你也有线性复杂度,因为你实际上是在原始数组上进行三遍。并不是每遍都涉及到每个元素,所以虽然在原始情况下它看起来像三次复杂度,但你 应该 没问题,但如果情况看起来不好,请考虑分析。
您可以加入然后重新拆分参数并使用三元运算符来减少行数:)
var found = [];
each(arguments.join(",").split(","), function(selector) {
each(handle(selector), function(element) {
return (found.indexOf(element) < 0) ? found.push(element) : null;
});
});
这是一个辅助函数,它可以将类似对象的数组转换为实际数组,然后遍历可迭代对象,将列表中的每个值提供给回调函数:
var each = function(iterable, callback) {
iterable = Array.prototype.concat.apply([], iterable);
for(var i = 0; i < iterable.length; i++) {
callback.apply(iterable[i], [iterable[i], i]);
}
return iterable;
};
这里我使用前面提到的辅助函数来遍历数组:
var found = [];
each(arguments, function(argument) {
each(argument.split(","), function(selector) {
each(handle(selector), function(element) {
if(found.indexOf(element) < 0) {
found.push(element);
}
});
});
});
第一个循环遍历参数。第二个循环拆分选择器,第三个循环遍历请求的元素并将它们添加到 found
数组(如果尚未添加)。
注意:handle
函数采用选择器(字符串)和 returns 使用 document.querySelectorAll
的元素列表。
此脚本有效,但问题是可读性和性能。
当有许多参数包含多个(~5-10)逗号分隔的选择器,然后由 handle
函数单独处理时,会出现性能问题。
我使用 类 而不是 id 解决了这个问题。
然后是可读性问题,我试图通过将第二个循环移到父循环之外来解决这个问题,但这需要创建更多变量,唯一的区别是改变了 where each
循环,这使得可读性更差,因为要阅读的代码更多。
问题:如何重构我的代码以减少嵌套循环的数量?
还有,第一个循环有必要吗?如果我不使用它,我将如何遍历参数以拆分它们以获得每个单独的选择器?我知道 split
方法适用于 String
类型,不能在数组上调用。
注意:我使用的是 vanilla JavaScript,不包括任何库、框架或外部脚本。
您似乎希望收集一些出现在某些顺序数据源中的值,例如
["A,B", "C,A,D", "A", "C,E,B"]
到集合(没有重复项)如
{"A", "B", "C", "D", "E"}
您可以在没有任何第三方库的情况下使用三个嵌套循环来做到这一点(无需担心性能 或 可读性):
const s = new Set();
for (let x of arguments) {
for (let g of x.split(",")) {
for (let i of g) {
s.add(i);
}
}
}
按功能编写,您可以将整个事情减少到:
new Set(arguments.join().split(','))
这当然假设您的任何选择器中都没有逗号。
这里的列表并不是真正的嵌套,因为您分三步完全处理了原始列表。细分:
- 原文:
[ 'A,B', 'C,A,D', 'A', 'C,E,B' ]
- 加入后:
'A,B,C,A,D,A,C,E,B'
- 拆分后:
[ 'A', 'B', 'C', 'A', 'D', 'A', 'C', 'E', 'B' ]
- 设置后:
Set { 'A', 'B', 'C', 'D', 'E' }
我认为即使在循环情况下你也有线性复杂度,因为你实际上是在原始数组上进行三遍。并不是每遍都涉及到每个元素,所以虽然在原始情况下它看起来像三次复杂度,但你 应该 没问题,但如果情况看起来不好,请考虑分析。
您可以加入然后重新拆分参数并使用三元运算符来减少行数:)
var found = [];
each(arguments.join(",").split(","), function(selector) {
each(handle(selector), function(element) {
return (found.indexOf(element) < 0) ? found.push(element) : null;
});
});