फ़िल्टर फ़ंक्शन द्वारा एक सरणी विभाजित करना


91

मेरे पास एक जावास्क्रिप्ट सरणी है जिसे मैं दो तत्वों में विभाजित करना चाहूंगा कि क्या प्रत्येक तत्व रिटर्न पर बुलाया गया फ़ंक्शन है trueया false। अनिवार्य रूप से, यह एक है array.filter, लेकिन मैं उन तत्वों को भी हाथ लगाना चाहूंगा जिन्हें फ़िल्टर किया गया था ।

वर्तमान में, मेरी योजना array.forEachप्रत्येक तत्व पर विधेय फ़ंक्शन का उपयोग और कॉल करना है। यह सही है या गलत इस पर निर्भर करते हुए, मैं वर्तमान तत्व को दो नए सरणियों में से एक पर धकेलूंगा। क्या ऐसा करने के लिए अधिक सुरुचिपूर्ण या अन्यथा बेहतर तरीका है? एक array.filterजहां एक और सरणी पर तत्व धक्का से पहले ही रिटर्न होगा false, उदाहरण के लिए?


यदि आप कुछ नमूना कोड पोस्ट कर सकते हैं, तो आपको बेहतर उत्तर देने में मदद मिलेगी!
— मार्क पीज़्ज़क - ट्रिलोन।

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

3
आप कॉलबैक में जो चाहें कर सकते हैं, .filterलेकिन पास के ऐसे प्रभावों को ट्रैक करना और समझना मुश्किल है। बस सरणी पर पुनरावृत्त करें और एक सरणी या किसी अन्य पर पुश करें।
— फेलिक्स क्लिंग

जवाबों:


75

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

8
मेरे लिए, लॉश पार्टीशन या सिर्फ forEach समझना आसान होगा, लेकिन फिर भी, अच्छा प्रयास
— Toni Leigh

15
यह मूल में हर तत्व के लिए दो नए सरणियों का निर्माण करेगा। जबकि एक सरणी में केवल दो तत्व होंगे, दूसरा सरणी के आकार के साथ बढ़ता है। इस प्रकार यह सुपर स्लो होगा और बहुत सारी मेमोरी को बेकार कर देगा। (आप एक पुश के साथ भी ऐसा कर सकते हैं और यह अधिक कुशल होगा।)
— स्टुअर्ट शेचटर

धन्यवाद, मेरा समय बचाया!
— 7urkm3n

यह वास्तव में उपयोगी है, ब्रेज़ा। दूसरों के लिए ध्यान दें: नीचे कुछ और पठनीय संस्करण हैं।
— रफी

38

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

16

आप इसके लिए कम उपयोग कर सकते हैं:

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

3
IMHO, पहला समाधान (पुश) बेहतर प्रदर्शन है क्योंकि सरणी आकार बढ़ता है।
— टूलमेकरसेव

@ टॉल्मेकरसेतुव आप और अधिक विस्तृत क्यों कर सकते हैं? मैंने शीर्ष उत्तर पर टिप्पणी भी पढ़ी लेकिन फिर भी उलझन में है कि क्यों
— २१:२५

2
@buncis। पहला दृष्टिकोण प्रत्येक तत्व की एक बार जांच करता है, बस उस तत्व को उपयुक्त सरणी पर धकेलता है। दूसरा दृष्टिकोण प्रत्येक तत्व के लिए निर्माण करता है [...left, current]या [...right, current]-। मैं सटीक इंटर्नल को नहीं जानता, लेकिन मुझे यकीन है कि निर्माण किसी तत्व को एक सरणी पर धकेलने की तुलना में अधिक महंगा है। सामान्य नियम के रूप में, पुनरावृत्ति पुनरावृत्ति की तुलना में अधिक महंगा है , क्योंकि इसमें हर बार "स्टैक फ्रेम" बनाना शामिल है।
— टूलमेकरसेव

14

यह रूबी के समान लगता है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 ] ]

11
आधुनिक पाठक के लिए, कृपया वैश्विक मानक पुस्तकालय वस्तुओं में तरीकों को न जोड़ें। यह खतरनाक है, और इसे अधिलेखित करने की संभावना है, जो रहस्यमय और टूटे हुए व्यवहार के लिए अग्रणी है। एक सादा पुराना फंक्शन, जो ठीक से स्कूप किया गया है, बहुत सुरक्षित है, और myFunc (array) को कॉल करना array.myFunc () से कम "एलिगेंट" नहीं है।
— Emmett R.

14

मैं इस छोटे आदमी के साथ आया था। यह आपके द्वारा वर्णित प्रत्येक और सभी के लिए उपयोग करता है, लेकिन यह मेरी राय में साफ और रसीला दिखता है।

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


1
यह समाधान उन लोगों में से कुछ से बेहतर है जिनके पास अधिक अपवोट्स हैं, IMHO। पढ़ने में आसान, सरणी के माध्यम से एक एकल पास बनाता है, और विभाजन परिणाम सरणियों का आवंटन और पुन: आवंटन नहीं करता है। मुझे यह भी पसंद है कि यह फ़िल्टर फ़ंक्शन (मान, सूचकांक और संपूर्ण सरणी) के तीन सामान्य फ़िल्टर मानों को उजागर करता है। यह इस फ़ंक्शन को अधिक पुन: प्रयोज्य बना देगा।
— speckledcarp

मुझे इसकी सादगी और लालित्य बहुत पसंद है। ऐसा कहने के बाद, मैंने पाया कि यह एक साधारण forलूप की तुलना में काफी धीमा है जैसा कि @qwertymk द्वारा एक पुराने उत्तर में है। उदाहरण के लिए १,००,००० तत्वों से युक्त यह मेरे सिस्टम पर दो बार धीमा था।
— 5

9

फ़िल्टर फ़ंक्शन में आप अपने झूठे आइटमों को दूसरे फ़ंक्शन के बाहर फ़ंक्शन में धकेल सकते हैं:

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बेहतर कोड पठनीयता के लिए उपयोग करना चाहिए ।


उपरोक्त पोस्टर से सहमत ... एक फिल्टर फ़ंक्शन में इस तरह के तर्क को रखना थोड़ा फूला हुआ और प्रबंधन करने में कठिन लगता है।
— TheUtherSide

मुझे लगता है कि फिल्टर समझ में आता है, आप उन्हें मूल सरणी से हटाना चाहते हैं ताकि यह एक फिल्टर हो
— Mojimi

5

आसान एक पढ़ने के लिए।

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)

6
नकारात्मक पक्ष यह है कि आप केवल एक के बजाय 2 छोरों बनाते हैं
— लॉरेंट

पठनीयता के लिए upvote, छोटे सरणी के लिए यह स्पष्ट रूप से अधिक भविष्य का प्रमाण है
— allan.simon

4

इसे इस्तेमाल करे:

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

डेमो


यह इंगित करते हुए कि सरणियों का फ़िल्टर फ़ंक्शन वास्तव में सभी ब्राउज़रों में समर्थित नहीं है (मैं आपको आईईएस में देख रहा हूं)
— TheZ

4

इस बारे में क्या?

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


2

यहां बहुत सारे उत्तर उपयोग किए जाते हैं Array.prototype.reduce एक उत्परिवर्तित संचायक का निर्माण करने के लिए करते हैं, और सही ढंग से इंगित करते हैं कि बड़े सरणियों के लिए, यह कहना अधिक कुशल है, एक प्रसार ऑपरेटर का उपयोग करके एक नया सरणी प्रत्येक पुनरावृत्ति की प्रतिलिपि बनाना। नकारात्मक पक्ष यह है कि यह लघु लैंबडा सिंटैक्स का उपयोग करके "शुद्ध" अभिव्यक्ति के रूप में सुंदर नहीं है।

लेकिन इसके आसपास एक तरीका कॉमा ऑपरेटर का उपयोग करना है। C जैसी भाषाओं में, अल्पविराम एक ऑपरेटर होता है जो हमेशा दाहिने हाथ का ऑपरेंड लौटाता है। आप इसका उपयोग एक अभिव्यक्ति बनाने के लिए कर सकते हैं जो एक शून्य फ़ंक्शन को कॉल करता है और एक मान लौटाता है।

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

मैंने इसे करना समाप्त कर दिया क्योंकि यह समझना आसान है (और पूरी तरह से टाइपस्क्रिप्ट के साथ टाइप किया गया)।

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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.