2015-12-21 3 views
26

У меня есть массив объектов, которые я хочу перебрать для создания нового фильтрованного массива. Но также, мне нужно отфильтровать некоторые из объектов из нового массива в зависимости от параметра. Я пробовал это:Карту и фильтровать массив одновременно в Javascript

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

Это хороший подход? Есть ли лучший метод? Я открыт для использования любой библиотеки, такой как lodash.

+0

Как насчет подхода «object.keys»? https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Object/keys – Julo0sS

+0

Используйте сокращение: https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce –

ответ

39

Вы должны использовать 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>

Подробнее: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

+0

Для меня первый arg, 'filter' - это объект. поэтому 'filter.push' для меня не определен. –

+0

У меня также была проблема с 'фильтром', являющимся объектом. Это было связано с тем, что я не передавал «начальное значение» - пустой массив ('[]') после функции уменьшения. , например. неправильное 'вар уменьшена = options.reduce (функция (фильтруется, опция) { ... });' правильно 'вар уменьшена = options.reduce (функция (фильтруется, опция) { .. }, []); ' –

1

Используйте Array.prototy.filter сам

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

Это ничего не отвечает. Вопрос заключается в том, как мы упростим две функции массива в одну. –

28

Использование уменьшить, Люк!

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

Используя сокращение, вы можете сделать это в одной функции Array.prototype. Это позволит получить все четные числа из массива.

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>

Вы можете использовать тот же метод и обобщать его для ваших объектов, как это.

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

arr теперь будет содержать отфильтрованные объекты.

2

С ES6 вы можете сделать это очень коротко:

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

+0

Это будет делать две петли, в зависимости от того, какой фильтр возвращается, все еще может поесть память. – hogan

0

В какой-то момент, не проще (или же просто) использовать 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>

Однако было бы неплохо, если бы был malter() или fap(), который объединяет функции map и filter. Он будет работать как фильтр, но вместо того, чтобы возвращать true или false, он возвращает любой объект или null/undefined.

0

Я оптимизировал ответы со следующими точками:

  1. переписывания if (cond) { stmt; } в cond && stmt;
  2. Использовать обычные ES6 Arrow Functions

Я представлю два решения, один с помощью forEach, другой с помощью reduce :

Solut иона 1: Использование 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);

Решение 2: Использование уменьшить

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

Я оставляю это до вас, чтобы решить, какое решение пойдите для.

+0

Почему бы вам не использовать 'cond & & stmt;'? Это гораздо труднее прочитать и не предлагает никаких преимуществ. – jlh

Смежные вопросы