[javascript] 필터 함수로 배열 나누기

각 요소에 대해 호출 된 함수가 true또는을 반환하는지 여부에 따라 두 개로 분할하려는 Javascript 배열이 false있습니다. 기본적으로 이것은이다 array.filter, 그러나 나는 또한 손에 필터링 된 요소를 가지고 싶습니다 아웃 .

현재 내 계획은 array.forEach각 요소에 대해 조건 자 함수 를 사용 하고 호출하는 것입니다. 이것이 참인지 거짓인지에 따라 현재 요소를 두 개의 새로운 배열 중 하나에 푸시합니다. 더 우아하거나 더 나은 방법이 있습니까? 예 를 들어 array.filter는 반환하기 전에 요소를 다른 배열로 푸시합니다 false.



답변

ES6를 사용하면 reduce로 스프레드 구문을 사용할 수 있습니다.

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

또는 한 줄로 :

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


답변

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


답변

이를 위해 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)) {
        return partition(tail, f, [[...left, current], right]);
    }
    return partition(tail, f, [left, [...right, current]]);
}


답변

이것은 Ruby의Enumerable#partition 방법 과 매우 유사하게 들립니다 .

함수가 부작용을 가질 수없는 경우 (즉, 원래 배열을 변경할 수없는 경우), 각 요소를 반복하고 요소를 두 배열 중 하나로 푸시하는 것보다 배열을 분할하는 더 효율적인 방법은 없습니다.

즉, Array이 기능을 수행 하는 방법을 만드는 것이 틀림없이 더 “우아하다” . 이 예제에서 필터 함수는 원래 배열의 컨텍스트에서 실행되고 (즉, this원래 배열이 됨) 요소와 요소의 인덱스를 인수로받습니다 ( jQuery의 each메서드 와 유사 함 ).

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


답변

이 작은 녀석을 생각해 냈습니다. 그것은 당신이 설명한 것과 같은 모든 것을 사용하지만 제 생각에는 깨끗하고 간결 해 보입니다.

//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);


답변

필터 함수에서 거짓 항목을 함수 외부의 다른 변수로 푸시 할 수 있습니다.

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더 나은 코드 가독성을 위해 사용해야한다고 생각합니다 .


답변

읽기 쉽습니다.

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)