这可能比我想象的要简单得多,但我一直在试用javascript中的.map()和.filter()函数.我想要做的是使用.filter()创建一个数组,并为与第一个过滤器的谓词不匹配的元素创建另一个数组.我到目前为止:
function test(array, predicate){
var filterTrue = array.filter(predicate);
var filterFalse = ??
// rest of method
}
Run Code Online (Sandbox Code Playgroud)
有没有办法将与谓词不匹配的项目转储到filterFalse?可能不言而喻,但谓词通常是某种功能
编辑:顺便说一下,我试过:
var filterFalse = array.filter(!predicate);
Run Code Online (Sandbox Code Playgroud)
但这似乎并不适用于我仍在努力理解的原因(对此的任何帮助也将非常感激)
在这种情况下,你就要去更好forEach,但我解决您为什么问题!predicate没有工作(以及你如何使一些喜欢它,做)以下为好.
首先,简单的forEach解决方案:
Prosiac:
function test(array, predicate){
var filterTrue = [];
var filterFalse = [];
array.forEach(function(value) {
if (predicate(value)) {
filterTrue.push(value);
} else {
filterFalse.push(value);
}
});
// rest of method
}
Run Code Online (Sandbox Code Playgroud)
多一点简洁:
function test(array, predicate){
var filterTrue = [];
var filterFalse = [];
array.forEach(function(value) {
(predicate(value) ? filterTrue : filterFalse).push(value);
});
// rest of method
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我试过:
Run Code Online (Sandbox Code Playgroud)var filterFalse = array.filter(!predicate);但这似乎并不适用于我仍在努力理解的原因
它必须是:
var filterFalse = array.filter(function(entry) {
return !predicate(entry);
});
Run Code Online (Sandbox Code Playgroud)
......这确实有效,但这意味着你要在数组中进行两次传递,并为每个元素调用谓词两次.这就是我推荐的原因forEach:只需要一次遍历数组,每次只有一次调用谓词.
你var filterFalse = array.filter(!predicate);不工作的原因是它接受predicate变量,它包含对函数的引用,并在逻辑上反转它!.非空对象引用(函数是对象)的逻辑反转版本是false,因此您实际上已经false进入filter.
更完整:一元将!其操作数强制转换为布尔值,然后返回它的反面(falsefor true和truefor false).因此,!predicate将导致false对任何价值predicate,它可以强制到true(又名"truthy"值),并会导致true对任何价值predicate,它可以强制到false(又名"falsey"值).那么什么是"真实"和"虚假"的价值观?所述"falsey"的值是0,"",null,undefined,NaN,和当然false; "truthy"值是所有其他值,包括所有非null对象引用.
如果您使用谓词进行编程并想要一种说"非谓词"的方法并获得一个给出反转结果的函数,那么您可以这样做:
function not(predicate) {
return function() {
return !predicate.apply(this, arguments);
};
}
Run Code Online (Sandbox Code Playgroud)
然后:
var filterFalse = array.filter(not(predicate));
Run Code Online (Sandbox Code Playgroud)
该not函数的工作原理如下:它返回一个新函数,当调用它时,它将调用你给它的谓词函数,传递this它所调用的值以及调用它的所有参数(via Function#apply - spec | MDN),逻辑反转它从谓词中获得的返回值,然后返回该反转值.
但同样,使用它需要两次通过数组.但是,有时使用高级抽象,这可能比forEach解决方案更可取.
最后,如果你这样做"要么/或"的东西很多,你当然可以做一个函数来做到这:
function divvyUp(array, predicate) {
var filterTrue = [], filterFalse = [];
array.forEach(function(value) {
(predicate(value) ? filterTrue : filterFalse).push(value);
});
return {
filterTrue: filterTrue,
filterFalse: filterFalse
};
}
Run Code Online (Sandbox Code Playgroud)
编辑:
下面是 lodash 中的 partition 方法在纯 JavaScript 中的实现,在 JSDoc 中使用 TypeScript 类型。它使用Array.prototype.reduce。正如 JSDoc 评论所说,此分区函数执行以下操作:
返回一个数组,其中包含索引 0 和 1 处的两个数组。索引 0 处的数组是通过返回真值
arr通过predicate真值测试的所有项目。索引 1 处的数组是通过返回假值arr而未能通过predicate真值测试的所有项目。
// ----- partition function declaration -----
/** Returns an array with two arrays at index
* 0 and 1. The array at index 0 is all the items
* in `arr` that passed the `predicate` truth test by
* returning a truthy value. The array at index 1 is all the items
* in `arr` that failed the `predicate` truth test by returning
* a falsy value.
* @template {any} T
* @param {Array<T>} arr
* @param {(el:T, index:number, arr:Array<T>) => any} predicate
* @returns {[Array<T>, Array<T>]}
*/
function partition(arr, predicate) {
return arr.reduce(
// this callback will be called for each element of arr
function(partitionsAccumulator, arrElement, i, arr) {
if (predicate(arrElement, i, arr)) {
// predicate passed push to left array
partitionsAccumulator[0].push(arrElement);
} else {
// predicate failed push to right array
partitionsAccumulator[1].push(arrElement);
}
// whatever is returned from reduce will become the new value of the
// first parameter of the reduce callback in this case
// partitionsAccumulator variable if there are no more elements
// this return value will be the return value of the full reduce
// function.
return partitionsAccumulator;
},
// the initial value of partitionsAccumulator in the callback function above
// if the arr is empty this will be the return value of the reduce
[[], []]
);
}
// ----- function usage examples -----
// This partition gets all numbers which are even in the
// first array (all these numbers returned true for the predicate)
// and returns all numbers which are odd in the second array
var res = partition([1, 2, 3], function(number) {
return number % 2 === 0;
});
console.log(res); // ? [[2], [1, 3]]
// This partition gets all indexes that are more than half
// way through the array.
res = partition([1, 2, 3, 4], function(number, index, array) {
return index > Math.floor(array.length / 2) - 1;
});
console.log(res); // ? [[3, 4], [1, 2]]
// This partition gets all strings with length greater than 4
res = partition(["bam!", "kazaam!", "blam!", "wam!", "jam!"], (string) => {
return string.length > 4;
});
console.log(res); // ? [["kazaam!", "blam!"], ["bam!", "wam!", "jam!"]]Run Code Online (Sandbox Code Playgroud)
使用 JSDoc 类型的好处是,如果你有一个像 VSCode 这样的编辑器,当你在 mac 上按下 command 或在 windows 上按下 ctrl 时,它会向你显示类型和描述。看起来像这样:
考虑到我在 JSDoc 注释中使用了模板 T,VSCode 足够聪明,因为该图中的参数 1 中的数组充满了数字,因此 T 是一个数字。如果您传入一个字符串数组,它将正确提示谓词el参数的类型和内部数组的返回项值作为字符串,因为它们也使用模板 T。
原答案
如果您还没有使用它们,那么讨厌提出库,但是lodash有一个函数可以完成这个称为partition 的功能。
_.partition([1, 2, 3], function(n) {
return n % 2;
});
// ? [[1, 3], [2]]
_.partition([1.2, 2.3, 3.4], function(n) {
return this.floor(n) % 2;
}, Math);
// ? [[1.2, 3.4], [2.3]]
Run Code Online (Sandbox Code Playgroud)
创建一个分成两组的元素数组,第一组包含元素谓词返回真值,而第二个包含元素谓词返回假值。谓词绑定到 thisArg 并使用三个参数调用:(值,索引|键,集合)。
如果为谓词提供了属性名称,则创建的 _.property 样式回调将返回给定元素的属性值。
如果还为 thisArg 提供了值,则创建的 _.matchesProperty 样式回调对于具有匹配属性值的元素返回 true,否则返回 false。
如果为谓词提供了对象,则创建的 _.matches 样式回调对于具有给定对象属性的元素返回 true,否则返回 false。参数
- 集合(数组|对象|字符串):要迭代的集合。
- [predicate=_.identity] (Function|Object|string):每次迭代调用的函数。
- [thisArg] (*):谓词的 this 绑定。
退货
(Array):返回分组元素的数组。
更多例子
var users = [
{ 'user': 'barney', 'age': 36, 'active': false },
{ 'user': 'fred', 'age': 40, 'active': true },
{ 'user': 'pebbles', 'age': 1, 'active': false }
];
var mapper = function(array) {
return _.pluck(array, 'user');
};
// using the `_.matches` callback shorthand
_.map(_.partition(users, { 'age': 1, 'active': false }), mapper);
// ? [['pebbles'], ['barney', 'fred']]
// using the `_.matchesProperty` callback shorthand
_.map(_.partition(users, 'active', false), mapper);
// ? [['barney', 'pebbles'], ['fred']]
// using the `_.property` callback shorthand
_.map(_.partition(users, 'active'), mapper);
// ? [['fred'], ['barney', 'pebbles']]
Run Code Online (Sandbox Code Playgroud)