web-gelistirme-sc.com

Bir diziyi filtre işlevine göre bölme

Her öğede çağrılan bir işlevin true veya false döndürdüğüne bağlı olarak ikiye bölmek istediğim bir Javascript dizim var. Temel olarak, bu bir array.filter, fakat elimde out olarak filtrelenen unsurların da elinizde olmasını istiyorum.

Şu anda, benim planım array.forEach kullanmak ve her bir öğe için yüklem işlevini çağırmak. Bunun doğru mu yanlış mı olduğuna bağlı olarak, şu anki elemanı iki yeni diziden birine iteceğim. Bunu yapmanın daha zarif veya daha iyi bir yolu var mı? Örneğin bir array.filter __ öğeyi false döndürmeden önce öğeyi başka bir diziye itecek, örneğin?

36
Mike Chen

ES6 ile spread dizgesinden yararlanarak azaltma yöntemini kullanabilirsiniz:

function partition(array, isValid) {
  return array.reduce(([pass, fail], elem) => {
    return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]];
  }, [[], []]);
}

const [pass, fail] = partition(myArray, (e) => e > 5);

Veya tek bir satırda:

const [pass, fail] = a.reduce(([p, f], e) => (e > 5 ? [[...p, e], f] : [p, [...f, e]]), [[], []]);
24
braza

lodash.partition öğesini kullanabilirsiniz.

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

veya 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' }  ]
22
Zoltan Kochan

Bu, Ruby'nin Enumerable#partition yöntemine çok benzer.

İşlev yan etkilere sahip olamazsa (yani, orijinal diziyi değiştiremez), o zaman diziyi bölümlemenin her öğenin üzerinde yinelemekten ve öğeyi iki dizinizden birine itmekten daha etkili bir yolu yoktur.

Olduğu söyleniyor, tartışmasız daha fazla "zarif" bu işlevi gerçekleştirmek için Array bir yöntem oluşturmak için. Bu örnekte, filtre işlevi orijinal dizinin bağlamında yürütülür (yani this orijinal dizi olur) ve öğeyi ve öğenin dizinini argümanlar olarak alır ( jQuery'nin each yöntemi ):

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 ] ]
14
Brandan

Bunun için azaltma kullanabilirsiniz:

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;
      }, [[],[]]
    );
 };
6
Yaremenko Andrii

Filtre işlevinde, yanlış öğelerinizi başka bir değişkene zorlayabilirsiniz:

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

Tabii ki value === false gerçek bir karşılaştırmaya ihtiyaç duyar;) 

Ancak, forEach gibi hemen hemen aynı işlemi yapar. Bence daha iyi kod okunabilirliği için forEach kullanmalısınız.

5
codename-

Bunu dene:

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;
}

DEMO

3
qwertymk

Bu küçük adamla geldim. Tanımladığınız her şey için kullanır, ancak bence temiz ve özlü görünmektedir.

//Partition function
function partition(array, filter) {
  let pass = [], fail = [];
  array.forEach((e, idx, arr) => (filter(e, idx, arr) ? pass : fail).Push(e));
  return [pass, fail];
}

//Run it with some dummy data and filter
const [lessThan5, greaterThanEqual5] = partition([0,1,4,3,5,7,9,2,4,6,8,9,0,1,2,4,6], e => e < 5);

//Output
console.log(lessThan5);
console.log(greaterThanEqual5);

2
UDrake

Birini okumak kolay.

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)
0
Matsumoto Kazuya

Bunu bitirdim çünkü anlaşılması kolay (ve tamamen TypeScript ile yazılmış).

const partition = <T>(array: T[], isValid: (element: T) => boolean): [T[], T[]] => {
  const pass: T[] = []
  const fail: T[] = []
  array.forEach(element => {
    if (isValid(element)) {
      pass.Push(element)
    } else {
      fail.Push(element)
    }
  })
  return [pass, fail]
}

// usage
const [pass, fail] = partition([1, 2, 3, 4, 5], (element: number) => number > 3)
0