program tip

동시에 배열 매핑 및 필터링

radiobox 2020. 8. 9. 10:17
반응형

동시에 배열 매핑 및 필터링


새 필터링 된 배열을 생성하기 위해 반복하려는 개체 배열이 있습니다. 또한 매개 변수에 따라 새 배열에서 일부 객체를 필터링해야합니다. 나는 이것을 시도하고있다 :

function renderOptions(options) {
    return options.map(function (option) {
        if (!option.assigned) {
            return (someNewObject);
        }
    });   
}

좋은 접근 방식입니까? 더 나은 방법이 있습니까? lodash와 같은 라이브러리를 사용할 수 있습니다.


Array.reduce이것을 위해 사용해야 합니다.

var options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];

var reduced = options.reduce(function(filtered, option) {
  if (option.assigned) {
     var someNewValue = { name: option.name, newProperty: 'Foo' }
     filtered.push(someNewValue);
  }
  return filtered;
}, []);

document.getElementById('output').innerHTML = JSON.stringify(reduced);
<h1>Only assigned options</h1>
<pre id="output"> </pre>


또는 감속기는 다음과 같이 순수한 함수가 될 수 있습니다.

var reduced = options.reduce(function(result, option) {
  if (option.assigned) {
    return result.concat({
      name: option.name,
      newProperty: 'Foo'
    });
  }
  return result;
}, []);

사용 감소, 루크!

function renderOptions(options) {
    return options.reduce(function (res, option) {
        if (!option.assigned) {
            res.push(someNewObject);
        }
        return res;
    }, []);   
}

ES6를 사용하면 매우 짧게 할 수 있습니다.

options.filter(opt => !opt.assigned).map(opt => someNewObject)


Array.prototype.flatMap 은 또 다른 옵션입니다.

options.flatMap(o => o.assigned ? [o.name] : []);

위에 링크 된 MDN 페이지에서 :

flatMap can be used as a way to add and remove items (modify the number of items) during a map. In other words, it allows you to map many items to many items (by handling each input item separately), rather than always one-to-one. In this sense, it works like the opposite of filter. Simply return a 1-element array to keep the item, a multiple-element array to add items, or a 0-element array to remove the item.


One line reduce with ES6 fancy spread syntax is here!

var options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];

const filtered = options
  .reduce((result, {name, assigned}) => [...result, ...assigned ? [name] : []], []);

console.log(filtered);


Use Array.prototy.filter itself

function renderOptions(options) {
    return options.filter(function(option){
        return !option.assigned;
    }).map(function (option) {
        return (someNewObject);
    });   
}

I optimized the answers with the following points:

  1. Rewriting if (cond) { stmt; } as cond && stmt;
  2. Use ES6 Arrow Functions

I'll present two solutions, one using forEach, the other using reduce:

Solution 1: Using forEach

var options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];
var reduced = []
options.forEach(o => {
  o.assigned && reduced.push( { name: o.name, newProperty: 'Foo' } );
} );
console.log(reduced);

Solution 2: Using reduce

var options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];
var reduced = options.reduce((a, o) => {
  o.assigned && a.push( { name: o.name, newProperty: 'Foo' } );
  return a;
}, [ ] );
console.log(reduced);

I leave it up to you to decide which solution to go for.


I'd make a comment, but I don't have the required reputation. A small improvement to Maxim Kuzmin's otherwise very good answer to make it more efficient:

const options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];

const filtered = options
  .reduce((result, { name, assigned }) => assigned ? result.concat(name) : result, []);

console.log(filtered);

Explanation

Instead of spreading the entire result over and over for each iteration, we only append to the array, and only when there's actually a value to insert.


Using reduce, you can do this in one Array.prototype function. This will fetch all even numbers from an array.

var arr = [1,2,3,4,5,6,7,8];

var brr  = arr.reduce(function(c,n){
  if(n%2!=0){
       return c;
    }
  c.push(n);
  return c;

},[]);

document.getElementById('mypre').innerHTML = brr.toString();
<h1>Get all even numbers</h1>
<pre id="mypre"> </pre>

You can use the same method and generalize it for your objects, like this.

var arr = options.reduce(function(c,n){
  if(somecondition){return c;}
  c.push(n); return c;
},[]);

arr will now contain the filtered objects.


At some point, isn't it easier(or just as easy) to use a forEach

var options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];

var reduced = []
options.forEach(function(option) {
  if (option.assigned) {
     var someNewValue = { name: option.name, newProperty: 'Foo' }
     reduced.push(someNewValue);
  }
});

document.getElementById('output').innerHTML = JSON.stringify(reduced);
<h1>Only assigned options</h1>
<pre id="output"> </pre>

However it would be nice if there was a malter() or fap() function that combines the map and filter functions. It would work like a filter, except instead of returning true or false, it would return any object or a null/undefined.

참고URL : https://stackoverflow.com/questions/34398279/map-and-filter-an-array-at-the-same-time

반응형