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

时间:2015-03-19 17:38:45

标签: javascript arrays

这可能比我想象的要简单得多,但我一直在试用javascript中的.map()和.filter()函数。我想要做的是使用.filter()创建一个数组,并为与第一个过滤器的谓词不匹配的元素创建另一个数组。到目前为止我所拥有的:

function test(array, predicate){
    var filterTrue = array.filter(predicate);
    var filterFalse = ??
    // rest of method
}

有没有办法将与谓词不匹配的项目转储到filterFalse?可能不言而喻,但谓词通常是某种功能

编辑:顺便说一下,我试过了:

var filterFalse = array.filter(!predicate);

但是,由于我仍然试图理解的原因,这似乎并不起作用(对此的任何帮助也将非常感激)

4 个答案:

答案 0 :(得分:6)

在这种情况下,您最好使用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
}

更简洁:

function test(array, predicate){
    var filterTrue = [];
    var filterFalse = [];
    array.forEach(function(value) {
        (predicate(value) ? filterTrue : filterFalse).push(value);
    });
    // rest of method
}

  

顺便说一下,我试过了:

var filterFalse = array.filter(!predicate);
     

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

必须是:

var filterFalse = array.filter(function(entry) {
    return !predicate(entry);
});

......这确实有效,但这意味着你要在数组中进行两次传递,并为每个元素调用谓词两次。这就是我推荐forEach的原因:只需要一次遍历数组,每次只有一次调用谓词。

var filterFalse = array.filter(!predicate);无法正常工作的原因是它采用predicate变量,其中包含对函数的引用,并使用!对其进行逻辑反转。非空对象引用(函数是对象)的逻辑反转版本为false,因此您实际上将false传递到filter

更完整:一元!将其操作数强制转换为布尔值,然后返回相反的值false truetrue false })。因此!predicate会导致false强制predicate强制true(也称为“真实”值)的任何值true,并且会导致predicate强制false的{​​{1}}值(又名“假”值)。那么什么是“真实”和“虚假”的价值观? “假名”值为0""nullundefinedNaN,当然还有false; “truthy”值是所有其他值,包括所有非null对象引用。

如果您使用谓词进行编程并想要一种说“非谓词”的方法并获得一个可以反转结果的函数,那么您可以这样做:

function not(predicate) {
    return function() {
        return !predicate.apply(this, arguments);
    };
}

然后:

var filterFalse = array.filter(not(predicate));

not函数的工作原理如下:它返回一个新函数,当调用它时,它将调用你给它的谓词函数,传递它被调用的this值和所有的函数它被调用的参数(通过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
    };
}

答案 1 :(得分:3)

如果你想要被拒绝的值,那么让过滤器接受一个返回谓词倒数的函数:

function test(array, predicate) {
    var filterTrue = array.filter(predicate);
    var filterFalse = array.filter(not(predicate));
   
   log(filterTrue, filterFalse);
}

function not(fn) {
    return function () {
        return !fn.apply(this, arguments);
    }
}

function log(filterTrue, filterFalse) {
     document.write('<pre> predicate true:' + JSON.stringify(filterTrue) + '</pre>');
     document.write('<pre> predicate false: ' + JSON.stringify(filterFalse) + '</pre>');
}

var array = [1, 2, 3, 4, 5];

function isEven(value) {
    return value % 2 === 0;
}

test(array, isEven);

答案 2 :(得分:2)

如果你还没有使用它们,就讨厌启动库,但是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]]
  

创建一个元素数组,分为两组,第一组   包含元素谓词返回truthy,而第二个   其中包含元素谓词返回falsey。谓词是   绑定到thisArg并使用三个参数调用:(value,index | key,   集合)。

     

如果为谓词提供了属性名称,则创建_.property   style callback返回给定元素的属性值。

     

如果还为thisArg提供了一个值,则创建_.matchesProperty   样式回调对具有匹配属性的元素返回true   值,否则为假。

     

如果为谓词提供了一个对象,则创建_.matches样式   对于具有该属性的元素,callback返回true   给定对象,否则为假。参数

     
      
  1. collection(Array | Object | string):要迭代的集合。
  2.   
  3. [predicate = _。identity](函数|对象|字符串):每次迭代调用的函数。
  4.   
  5. [thisArg](*):谓词的这种绑定。
  6.         

    返回

         

    (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']]

答案 3 :(得分:0)

&#13;
&#13;
function test(array, predicate){
    var filterTrue = array.filter(predicate);
    var filterFalse = array.filter(function(data) { return !predicate(data); })
    return { filterTrue: filterTrue, filterFalse: filterFalse }
}

mya = [ { id:1, desc: "one" }, {  id:2, desc: "two"  }, {  id:3, desc: "three" }];

console.info(test(mya, function(data) { return data.id == 1; }))
&#13;
&#13;
&#13;

颠倒谓词。