Javascript:将不匹配过滤谓词的元素放入单独的数组中

jba*_*991 9 javascript arrays

这可能比我想象的要简单得多,但我一直在试用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)

但这似乎并不适用于我仍在努力理解的原因(对此的任何帮助也将非常感激)

T.J*_*der 8

在这种情况下,你就要去更好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)

顺便说一句,我试过:

var filterFalse = array.filter(!predicate);
Run Code Online (Sandbox Code Playgroud)

但这似乎并不适用于我仍在努力理解的原因

它必须是:

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 truetruefor 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)


Joh*_*ohn 5

编辑

下面是 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 时,它会向你显示类型和描述。看起来像这样:

分区函数 VSCode 类型输出

考虑到我在 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。参数

  1. 集合(数组|对象|字符串):要迭代的集合。
  2. [predicate=_.identity] (Function|Object|string):每次迭代调用的函数。
  3. [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)