programing

배열을 필터 함수로 나눕니다.

lovejava 2023. 10. 11. 20:21

배열을 필터 함수로 나눕니다.

각 가 를 두 .true아니면false은 .array.filter, 하지만 저는 걸러진 요소들도 손에 쥐고 싶습니다.

를 입니다.array.forEach각 요소에서 술어 함수를 호출합니다.이것이 참인지 거짓인지에 따라 현재 요소를 두 개의 새로운 배열 중 하나에 밀어 넣겠습니다.더 우아하거나 더 나은 방법이 있을까요?array.filter서 는다를 .false요?

ES6를 사용하면 확산 구문을 다음과 같이 줄일 수 있습니다.

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.

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

내가 생각해낸 작은 남자.말씀하신 것처럼 하나하나 다 쓰이지만, 제 생각에는 깨끗하고 간결해 보입니다.

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

축소를 사용할 수 있습니다.

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

또는 타이프스크립트를 사용하는 경우:

const partition = <T,>(
  array: T[],
  callback: (element: T, index: number, array: T[]) => boolean
) => {
  return array.reduce(function(result, element, i) {
    callback(element, i, array)
      ? result[0].push(element) 
      : result[1].push(element);

    return result;
  }, [[],[]]);
};

예:

const groceries = [
  { type: "apple" },
  { type: "pear" },
  { type: "banana" }
]

const [apples, others] = partition(
  groceries, 
  (item) => item.type === "apple",
);

// => apples: [{ type: "apple" }]
// => others: [{ type: "pear" }, { type: "banana" }] 

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

이것은 루비의 방법과 매우 비슷하게 들립니다.

함수가 부작용을 일으킬 수 없는 경우(즉, 원래 배열을 변경할 수 없는 경우), 각 요소를 반복하여 요소를 두 개의 배열 중 하나로 밀어 넣는 것보다 더 효율적인 배열 분할 방법은 없습니다.

는 하지만, 에 대한 방법을 만드는 이 "" 고하는 더고 말할 수 있습니다.Array이 기능을 수행할 수 있습니다.됩니다(즉))에서this원래 배열)이 될 것이며, 요소와 요소의 인덱스를 인수로 받습니다(jQuery의 메서드와 유사).

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

필터 함수에서는 거짓 항목을 다른 변수 외부 함수에 밀어 넣을 수 있습니다.

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더 나은 코드 가독성을 위해.

서 많은 됩니다.Array.prototype.reduce가변 어큐뮬레이터를 구축하고, 대규모 어레이의 경우 각 반복마다 새로운 어레이를 복사하기 위해 스프레드 연산자를 사용하는 것보다 이것이 더 효율적이라는 점을 정확하게 지적합니다.단점은 짧은 람다 구문을 사용하는 "순수한" 표현만큼 예쁘지 않다는 것입니다.

하지만 그 방법은 쉼표 연산자를 사용하는 것입니다.C 언어에서 쉼표는 항상 오른쪽 피연산자를 반환하는 연산자입니다.이를 통해 void 함수를 호출하고 값을 반환하는 식을 만들 수 있습니다.

function partition(array, predicate) {
    return array.reduce((acc, item) => predicate(item)
        ? (acc[0].push(item), acc)
        : (acc[1].push(item), acc), [[], []]);
}

부울 식이 0과 1의 숫자를 암시적으로 캐스트한다는 점을 이용하면, 더 간결하게 표현할 수 있습니다. 비록 제가 보기에는 그렇게 가독성이 있다고 생각하지는 않지만 말입니다.

function partition(array, predicate) {
    return array.reduce((acc, item) => (acc[+!predicate(item)].push(item), acc), [[], []]);
}

용도:

const [trues, falses] = partition(['aardvark', 'cat', 'apple'], i => i.startsWith('a'));
console.log(trues); // ['aardvark', 'apple']
console.log(falses); // ['cat']

이거는?

[1,4,3,5,3,2].reduce( (s, x) => { s[ x > 3 ].push(x); return s;} , {true: [], false:[]} )

아마도 이것이 퍼짐 연산자보다 더 효율적일 것입니다.

아니면 조금 더 짧지만 더 못생겼습니다.

[1,4,3,5,3,2].reduce( (s, x) => s[ x > 3 ].push(x)?s:s , {true: [], false:[]} )

시도해 보기:

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

데모

읽기 쉬운 것.

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)

이해하기 쉽기 때문에 이렇게 하게 되었습니다.

const partition = (array, isValid) => {
  const pass = []
  const fail = []
  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) => element > 3)

그리고 타이프스크립트 유형을 포함한 동일한 방법:

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) => element > 3)

원-라이너 파티션

const partitionBy = (arr, predicate) =>
    arr.reduce((acc, item) => (acc[+!predicate(item)].push(item), acc), [[], []]);

데모

// to make it consistent to filter pass index and array as arguments
const partitionBy = (arr, predicate) =>
    arr.reduce(
        (acc, item, index, array) => (
            acc[+!predicate(item, index, array)].push(item), acc
        ),
        [[], []]
    );

console.log(partitionBy([1, 2, 3, 4, 5], x => x % 2 === 0));
console.log(partitionBy([..."ABCD"], (x, i) => i % 2 === 0));

Typescript(v4.5)용

const partitionBy = <T>(
  arr: T[],
  predicate: (v: T, i: number, ar: T[]) => boolean
) =>
  arr.reduce(
    (acc, item, index, array) => {
      acc[+!predicate(item, index, array)].push(item);
      return acc;
    },
    [[], []] as [T[], T[]]
  );

여기서 대부분의 답은 단순히 Array.reduce를 변형한 것으로 이를 수행하는 올바른 방법입니다.자바스크립트에서 배열을 분할하기 위한 간단한 API로 이 모든 것을 추상화하는 작은 라이브러리를 작성했습니다.또한 웹 워커(또는 노드의 웹 쓰레드)를 생성하여 어레이를 파티션 비동기화할 수 있습니다.

const someArray = [1, ... , 100]

console.log('--- start ---');

const reduced = someArray.reduce((reducer, i) => {
      // Different variations of fancy code can go here that all do the same thing
      if (i < 33) reducer[0].push(i)
      else if (i => i > 32 && i < 66) reducer[1].push(i)
      else if (i => i > 67) reducer[2].push(i)
      return reducer
    }, [[], [], []])

console.log('array.reduce done processing');
console.log('--- UI element loaded ---');

'--- start ---'
'array.reduce done processing'
'--- UI element loaded ---'

라이브러리를 사용하여 동일한 작업을 수행하는 방법은 다음과 같습니다.

const someArray = [1, ... , 100]

console.log('--- start ---');

partition()
    .async()
    .add(i => i < 33)
    .add(i => i > 32 && i < 66)
    .add(i => i > 67)
    .split(someArray)
    .then(result => {
      console.log('Partitions done processing');
    });

console.log('--- UI element loaded ---');

'--- start ---'
'--- UI element loaded ---'
'Partitions done processing'

둘 다의 출력은 세 개의 배열 파티션이 됩니다.

[
  [1, ..., 32],
  [33, ..., 65],
  [66, ..., 100]
]

@Yaremenko Andrii의 첫 번째 솔루션과 동일하지만 구문이 더 짧은 Lodash 파티션 대안

function partition(arr, callback) {
  return arr.reduce(
    (acc, val, i, arr) => {
      acc[callback(val, i, arr) ? 0 : 1].push(val)
      return acc
    },
    [[], []]
  )
}

이미 여러 개의 솔루션이 있다는 것을 알고 있지만 위의 답변 중 가장 좋은 부분을 자유롭게 조합하여 Typescript에 확장 방법을 사용했습니다.복사해서 붙여넣기만 하면 작동합니다.

declare global {

  interface Array<T> {
    partition(this: T[], predicate: (e: T) => boolean): T[][];
  }

}

if(!Array.prototype.partition){

  Array.prototype.partition = function<T>(this: T[], predicate: (e: T) => boolean): T[][] {

    return this.reduce<T[][]>(([pass, fail], elem) => {
      (predicate(elem) ? pass : fail).push(elem);
      return [pass, fail];
    }, [[], []]);

  }
}

용도:


const numbers = [1, 2, 3, 4, 5, 6];
const [even, odd] = numbers.partition(n => n % 2 === 0);

언급URL : https://stackoverflow.com/questions/11731072/dividing-an-array-by-filter-function