उसी समय किसी सरणी को मैप और फ़िल्टर करें


155

मेरे पास ऑब्जेक्ट्स की एक सरणी है जिसे मैं नए फ़िल्टर किए गए सरणी का उत्पादन करने के लिए पुनरावृत्त करना चाहता हूं। लेकिन इसके अलावा, मुझे एक पैरामीटर के आधार पर नई सरणी से कुछ ऑब्जेक्ट्स को फ़िल्टर करने की आवश्यकता है। मैं यह कोशिश कर रहा हूँ:

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

क्या यह एक अच्छा तरीका है? क्या कोई बेहतर तरीका है? मैं किसी भी पुस्तकालय का उपयोग करने के लिए खुला हूं जैसे कि लॉश।


एक "object.keys" दृष्टिकोण के बारे में क्या? developer.mozilla.org/fr/docs/Web/JavaScript/Reference/…
Julo0sS


3
.reduce()निश्चित रूप से तेज है .filter(...).map(...)जो मैंने कहीं और सुझाया है। मैंने stackoverflow.com/a/47877054/2379922
जस्टिन एल।

जवाबों:


219

आपको इसके लिए उपयोग करना चाहिए 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>


वैकल्पिक रूप से, reducer एक शुद्ध कार्य हो सकता है, जैसे

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

2
मेरे लिए, पहला arg, filteredएक ऑब्जेक्ट है। इसलिए filtered.pushमेरे लिए अपरिभाषित है।
रहमतुल्ला एम।

4
मेरे पास filteredएक वस्तु होने के साथ एक मुद्दा भी था । ऐसा इसलिए था क्योंकि मैं []कम फ़ंक्शन के बाद "प्रारंभिक मान" - खाली सरणी ( ) में पास नहीं हो रहा था । उदाहरण के लिए गलत var reduced = options.reduce(function(filtered, option) { ... }); सही var reduced = options.reduce(function(filtered, option) { ... }, []);
जॉन हिगिंस

यहाँ कोई कारण नहीं reduceहै, आप बस उपयोग के forEachबाद से हर पुनरावृत्ति में आप सरणी बदल सकते हैं filteredऔर इस प्रकार यह शुद्ध कार्यात्मक नहीं है। यह अधिक पठनीय और कॉम्पैक्ट घटना होगी।
मार्को

1
@ मर्को मैंने एक शुद्ध रेड्यूसर भी पेश किया। PTAL।
thefourtheye

हां जो अभी शुद्ध है। आपके प्रयास के लिए +1। ऐसा नहीं है कि मैं शुद्ध कार्यात्मक प्रोग्रामिंग अधिवक्ता हूं, इससे बहुत दूर, मैं अभी बिंदु नहीं देख सकता था :) लेकिन वास्तव में मैंने इसे देखने के बाद आपकी चाल का उपयोग किया है, क्योंकि यह दिए गए स्थिति में इतना आसान था। लेकिन इस कार्य के लिए आप फ्लैटपाइप फ़ंक्शन पर एक नज़र डालना चाहते हैं, मुझे लगता है कि आपके द्वारा अपना उत्तर देने के बाद भी यह मानक में आया (इस कारण भी कुछ ब्राउज़रों द्वारा असमर्थित हो सकता है)। यह अधिक सुस्पष्ट होना चाहिए क्योंकि इस तरह के समवर्ती सरणियों से O (n ^ 2) कार्य O (n) कार्य से बाहर हो जाता है।
मार्को

43

उपयोग कम करें, ल्यूक!

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

30

2019 के बाद से, Array.prototype.flatMap अच्छा विकल्प है।

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

ऊपर लिंक एमडीएन पृष्ठ से:

flatMapमानचित्र के दौरान वस्तुओं को जोड़ने और हटाने के तरीके के रूप में उपयोग किया जा सकता है। दूसरे शब्दों में, यह आपको हमेशा एक-से-एक के बजाय कई वस्तुओं को कई वस्तुओं (प्रत्येक इनपुट आइटम को अलग से संभालकर) को मैप करने की अनुमति देता है। इस अर्थ में, यह फिल्टर के विपरीत की तरह काम करता है। केवल आइटम रखने के लिए 1-तत्व सरणी लौटें, आइटम जोड़ने के लिए एक बहु-तत्व सरणी या आइटम को निकालने के लिए 0-तत्व सरणी।


5
महान समाधान! लेकिन, पाठक ध्यान में रखते हैं कि flatMapहाल ही में पेश किया गया था और इसका ब्राउज़र समर्थन सीमित है । आप आधिकारिक पॉलीफ़िल / शिम का उपयोग करना चाह सकते हैं: फ्लैटपाइप और फ्लैट
अरल

24

ES6 के साथ आप इसे बहुत कम कर सकते हैं:

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


25
यह दो लूप करेगा, जो इस बात पर निर्भर करता है कि फ़िल्टर रिटर्न अभी भी मेमोरी खा सकता है।
होगन

1
@ होगन लेकिन यह मूल प्रश्न का सही उत्तर (इष्टतम समाधान नहीं हो सकता है)
विक्रमवी

1
@vikramvi आपके नोट के लिए धन्यवाद। बात यह है, हम टन के साथ एक ही चीजें हासिल कर सकते हैं और Id सबसे अच्छा पसंद करते हैं।
होगन

10

reduceES6 फैंसी प्रसार सिंटैक्स के साथ एक लाइन यहाँ है!

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


1
वाकई बहुत अच्छा @ मैक्सिम! मैं इस upvote! लेकिन ... प्रत्येक तत्व को जोड़ने पर, इसमें सभी तत्वों को फैलाना पड़ता है result... filter(assigned).map(name)समाधान की तरह है
0zkr PM

अच्छा है। यह महसूस करने के लिए मुझे एक सेकंड में ले गया कि क्या चल रहा है ...assigned ? [name] : []- यह अधिक पठनीय हो सकता है...(assigned ? [name] : [])
जोहान्सजा

5

मैं एक टिप्पणी करूँगा, लेकिन मेरे पास आवश्यक प्रतिष्ठा नहीं है। मैक्सिम कुज़मिन के एक छोटे से सुधार ने इसे और अधिक कुशल बनाने के लिए बहुत अच्छा जवाब दिया:

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

व्याख्या

प्रत्येक पुनरावृत्ति के लिए पूरे परिणाम को बार-बार फैलाने के बजाय, हम केवल सरणी में जोड़ते हैं, और केवल तब जब डालने के लिए वास्तव में एक मूल्य होता है।



2

कुछ बिंदु पर, इसका उपयोग करना आसान नहीं है (या बस उतना ही आसान है) 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काम करता है। यह एक फिल्टर की तरह काम करेगा, सच या झूठ को वापस करने के बजाय, यह किसी भी वस्तु या अशक्त / अपरिभाषित को लौटाएगा।


आप अपने मेमों की जांच करना चाहते हैं ... ;-)
Arel

2

मैंने निम्नलिखित बिंदुओं के साथ उत्तरों को अनुकूलित किया:

  1. के if (cond) { stmt; }रूप में फिर सेcond && stmt;
  2. ES6 एरो फ़ंक्शंस का उपयोग करें

मैं दो समाधान प्रस्तुत करूंगा, एक forEach का उपयोग कर, दूसरा कम उपयोग करने वाला :

समाधान 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);

मैं आपको यह तय करने के लिए छोड़ देता हूं कि किस समाधान के लिए जाना है।


1
पृथ्वी पर आप क्यों इस्तेमाल करेंगे cond && stmt;? यह पढ़ना बहुत मुश्किल है और इसमें कोई लाभ नहीं है।
jlh

1

कम करने का उपयोग करते हुए, आप इसे एक Array.prototype फ़ंक्शन में कर सकते हैं। यह एक सरणी से सभी संख्याओं को प्राप्त करेगा।

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

var brr = arr.reduce((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 अब फ़िल्टर्ड ऑब्जेक्ट होंगे।


0

प्रत्यक्ष उपयोग .reduceको पढ़ने में मुश्किल हो सकती है, इसलिए मैं एक फ़ंक्शन बनाने की सलाह दूंगा जो आपके लिए रीड्यूसर उत्पन्न करता है:

function mapfilter(mapper) {
  return (acc, val) => {
    const mapped = mapper(val);
    if (mapped !== false)
      acc.push(mapped);
    return acc;
  };
}

इसका उपयोग ऐसे करें:

const words = "Map and filter an array #javascript #arrays";
const tags = words.split(' ')
  .reduce(mapfilter(word => word.startsWith('#') && word.slice(1)), []);
console.log(tags);  // ['javascript', 'arrays'];
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.