131

true各要素で呼び出された関数がまたはを返すかどうかに基づいて、2 つに分割したい Javascript 配列がありますfalse。基本的にこれは ですが、フィルターで除外さarray.filterた要素も手元に置いておきたいと思います。

現在、私の計画は、array.forEach各要素で述語関数を使用して呼び出すことです。これが true か false かに応じて、現在の要素を 2 つの新しい配列のいずれかにプッシュします。これを行うためのよりエレガントな、またはより良い方法はありますか? たとえばarray.filter、要素を返す前に要素を別の配列にプッシュする場所は?false

4

14 に答える 14

53

lodash.partitionを使用できます

var users = [
  { 'user': 'barney',  'age': 36, 'active': false },
  { 'user': 'fred',    'age': 40, 'active': true },
  { 'user': 'pebbles', 'age': 1,  'active': false }
];

_.partition(users, function(o) { return o.active; });
// → objects for [['fred'], ['barney', 'pebbles']]

// The `_.matches` iteratee shorthand.
_.partition(users, { 'age': 1, 'active': false });
// → objects for [['pebbles'], ['barney', 'fred']]

// The `_.matchesProperty` iteratee shorthand.
_.partition(users, ['active', false]);
// → objects for [['barney', 'pebbles'], ['fred']]

// The `_.property` iteratee shorthand.
_.partition(users, 'active');
// → objects for [['fred'], ['barney', 'pebbles']]

またはramda.partition

R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']);
// => [ [ 'sss', 'bars' ],  [ 'ttt', 'foo' ] ]

R.partition(R.contains('s'), { a: 'sss', b: 'ttt', foo: 'bars' });
// => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' }  ]
于 2016-04-23T09:04:31.127 に答える
21

reduce を使用できます。

function partition(array, callback){
  return array.reduce(function(result, element, i) {
    callback(element, i, array) 
      ? result[0].push(element) 
      : result[1].push(element);
    
        return result;
      }, [[],[]]
    );
 };

アップデート。ES6 構文を使用すると、再帰を使用してそれを行うこともできます (反復ごとに新しい配列を作成しないように更新されています)。

function partition([current, ...tail], f, left = [], right = []) {
    if(current === undefined) {
        return [left, right];
    }
    if(f(current)) {
        left.push(current);
        return partition(tail, f, left, right);
    }
    right.push(current);
    return partition(tail, f, left, right);
}
于 2017-02-17T13:28:10.003 に答える
14

これは、 Ruby のEnumerable#partition方法と非常によく似ています。

関数が副作用を持つことができない場合 (つまり、元の配列を変更できない場合)、各要素を繰り返し処理し、その要素を 2 つの配列のいずれかにプッシュする以外に、配列を分割する効率的な方法はありません。

Arrayそうは言っても、この機能を実行するメソッドを作成する方が間違いなく「エレガント」です。この例では、フィルター関数は元の配列のコンテキストで実行され (つまり、this元の配列になります)、要素と要素のインデックスを引数として受け取ります ( jQuery のeachmethodと同様):

Array.prototype.partition = function (f){
  var matched = [],
      unmatched = [],
      i = 0,
      j = this.length;

  for (; i < j; i++){
    (f.call(this, this[i], i) ? matched : unmatched).push(this[i]);
  }

  return [matched, unmatched];
};

console.log([1, 2, 3, 4, 5].partition(function (n, i){
  return n % 2 == 0;
}));

//=> [ [ 2, 4 ], [ 1, 3, 5 ] ]
于 2012-07-30T23:59:04.763 に答える
11

フィルター関数では、偽のアイテムを関数外の別の変数にプッシュできます。

var bad = [], good = [1,2,3,4,5];
good = good.filter(function (value) { if (value === false) { bad.push(value) } else { return true});

もちろんvalue === false、本当の比較である必要があります;)

しかし、それは のようにほとんど同じ操作を行いforEachます。forEachコードの可読性を高めるために使用する必要があると思います。

于 2012-07-30T23:30:00.977 に答える
5

読みやすい一冊。

const partition = (arr, condition) => {
    const trues = arr.filter(el => condition(el));
    const falses = arr.filter(el => !condition(el));
    return [trues, falses];
};

// sample usage
const nums = [1,2,3,4,5,6,7]
const [evens, odds] = partition(nums, (el) => el%2 == 0)
于 2019-02-12T15:17:01.190 に答える
4

これを試して:

function filter(a, fun) {
    var ret = { good: [], bad: [] };
    for (var i = 0; i < a.length; i++)
        if (fun(a[i])
            ret.good.push(a[i]);
        else
            ret.bad.push(a[i]);
    return ret;
}

デモ

于 2012-07-30T23:25:48.757 に答える