带选择器的JavaScriptforEach——函数替换JavaScriptif语句



我最近写了以下代码:

function genBoard(width, height, numMines) {
let mineField = _.shuffle(Array(numMines).fill('*').concat(Array(width*height - numMines).fill(0)));
mineField.forEach((elem, pos) => {
if (elem == '*') {
let blastArea = [pos-width-1, pos-width, pos-width+1, pos-1, pos+1, pos+width-1, pos+width, pos+width+1];
blastArea.filter(p => p>=0 && p<width*height && mineField[p] != '*').forEach(p => mineField[p] += 1);
}
});
_.chunk(mineField, width).forEach(row => console.log(row.join('')));
}

注意,我使用的是来自lodash的_.shuffle_.chunk

我想以尽可能实用的方式来做这件事。所以我希望中间部分更像这样:

mineField.forEachFiltered((elem, pos) => {
let blastArea = [pos-width-1, pos-width, pos-width+1, pos-1, pos+1, pos+width-1, pos+width, pos+width+1];
blastArea.filter(p => p>=0 && p<width*height && mineField[p] != '*').forEach(p => mineField[p] += 1);
},
elem => elem == '*'
);

换句话说,forEachFiltered接受两个函数(而不是forEach接受一个),其中第二个函数是选择器,或者您可以将其称为谓词。如果您检查代码,您会发现我不能方便地使用forEachfilter的组合,因为我需要知道我在原始数组中的位置。我试过在谷歌上搜索,但在任何地方都没有找到forEachFiltered的概念,在lodash中也没有。我必须写那个函数吗?或者有其他方法(或者只使用if语句)吗?

p.S.:值为10、6、24的示例输出:

*2233222**
32****3*6*
312445*5**
5322*4*5**
***22*35**
432112*3*3

附言:用最简单的方式问我这个问题,你是怎么做["my", "array", "of", "whatever"].forEach(func, selector)的?

基于Array.prototype.forEach的polyfill编写自己的forEachFiltered实现是相当琐碎的。

Object.defineProperty(Array.prototype, 'forEachFiltered', {
value: function (func, predicate, thisArg) {
var array = Object(this),
index = 0,
length = array.length >>> 0,
value;
while (index < length) {
if (index in array) {
value = array[index];
if (predicate.call(thisArg, value, index, array)) {
func.call(thisArg, value, index, array);
}
}
index++;
}
}
});

或者您可以将其实现为Array.prototype.forEach:的包装器

Object.defineProperty(Array.prototype, 'forEachFiltered', {
value: function (func, predicate, thisArg) {
this.forEach(function () {
if (predicate.apply(this, arguments)) {
func.apply(this, arguments);
}
}, thisArg);
}
});

我还没有看到任何具有迭代函数的javascript库能像您建议的那样工作(除了普通函数外,还采用了谓词函数)。另一方面,Common Lisp具有类似substitute-if的功能(http://www.lispworks.com/documentation/HyperSpec/Body/f_sbs_s.htm#substitute-if),它们是相似的(事实上有几个可选的参数,可以进一步完善它们的行为),但即使如此,它也没有任何类似于forEachFiltered函数的功能。首先,与JS不同,Common Lisp迭代器函数根本不在任何位置传递。

无论如何,在你的具体情况下,我想说,你可以全面map来生成一个对象列表,每个对象代表一个单元格,包含单元格的内容以及单元格在雷区中的坐标。然后,您可以使用filter来生成一个仅包含具有地雷的单元格的列表,并在其中使用forEach来计算邻接。这与使用您正在考虑的forEachFiltered函数不太一样,但允许您做自己想做的事情。你可能会反对这样传递坐标感觉很奇怪,事实上可能确实如此。不过,我想说,这正是你开始使用的嵌套循环的对偶。

另一种选择是编写迭代函数,模仿Javascript的本地迭代方法,但当您在n维数组上迭代时,它会传递给您广义的n维坐标。那将是一个不错的小图书馆。

最新更新