ब्रेक कम () विधि जल्दी कैसे करें?


94

मैं reduce()विधि की पुनरावृत्ति कैसे तोड़ सकता हूं ?

for:

for (var i = Things.length - 1; i >= 0; i--) {
  if(Things[i] <= 0){
    break;
  }
};

reduce()

Things.reduce(function(memo, current){
  if(current <= 0){
    //break ???
    //return; <-- this will return undefined to memo, which is not what I want
  }
}, 0)

currentऊपर दिए गए कोड में क्या है ? मैं नहीं देखता कि ये कैसे काम कर सकते हैं। किसी भी मामले में वहाँ तरीकों कि जल्दी की तरह तोड़ कर रहे हैं some, every,find
elclanrs

someऔर everyबूलियन्स लौटाएं और findएक भी रिकॉर्ड लौटाएं, जो मैं चाहता हूं वह एक ज्ञापन तैयार करने के लिए ऑपरेशन चलाना है। currentcurrentValue है। संदर्भ
जूलियो मरिंस

मेरा मतलब है कि currentकोड के पहले टुकड़े में क्या है ?
एलक्लेनर्स

अद्यतन, इस उत्तर के लिए धन्यवाद
जूलियो मरीन

2
जवाब है कि आप जल्दी से नहीं तोड़ सकते हैं reduce, आपको बिलिन कार्यों के साथ एक और तरीका खोजना होगा जो जल्दी से बाहर निकलता है या अपना सहायक बनाता है, या लॉश या कुछ का उपयोग करता है। क्या आप जो करना चाहते हैं, उसका पूरा उदाहरण पोस्ट कर सकते हैं?
एलक्लेनर्स

जवाबों:


93

अपडेट करें

कुछ टिप्पणीकार एक अच्छी बात करते हैं कि .reduce()तर्क के अंदर जल्दी तोड़ने के लिए मूल सरणी को उत्परिवर्तित किया जा रहा है।

इसलिए, मैं इस सवाल का जवाब भी संशोधन किया है थोड़ा एक जोड़कर .slice(0)एक अनुवर्ती पर कॉल करने से पहले .reduce(), कदम मूल सरणी की एक प्रतिलिपि प्राप्त होता है। नोट : समान कार्य को पूरा करने वाले समान ऑप्स slice()(कम स्पष्ट), और प्रसार ऑपरेटर [...array]( थोड़ा कम प्रदर्शन करने वाले ) हैं। ध्यान रखें, ये सभी समग्र रनटाइम + 1 * (O (1)) में रैखिक समय का एक अतिरिक्त स्थिर कारक जोड़ते हैं।

प्रतिलिपि, मूल उत्परिवर्तन से मूल सरणी को संरक्षित करने का कार्य करती है जो पुनरावृति से अस्वीकृति का कारण बनती है।

const array = ['9', '91', '95', '96', '99'];
const x = array
    .slice(0)                         // create copy of "array" for iterating
    .reduce((acc, curr, i, arr) => {
       if (i === 2) arr.splice(1);    // eject early by mutating iterated copy
       return (acc += curr);
    }, '');

console.log("x: ", x, "\noriginal Arr: ", array);
// x:  99195
// original Arr:  [ '9', '91', '95', '96', '99' ]


पुराना

आप कम फ़ंक्शन के 4 वें तर्क को बदलकर एक .reduce () मंगलाचरण के किसी भी पुनरावृत्ति पर टूट सकते हैं: "सरणी"। एक कस्टम कम समारोह के लिए कोई ज़रूरत नहीं है। मापदंडों की पूरी सूची के लिए डॉक्स देखें .reduce()

Array.prototyp.reduce ((एसीसी, कर्व, आई, एरे))

4 वाँ तर्क वह सरणी है जिसे अधिक प्रसारित किया जा रहा है।

const array = ['9', '91', '95', '96', '99'];
const x = array
.reduce((acc, curr, i, arr) => {
    if(i === 2) arr.splice(1);  // eject early
    return acc += curr;
  }, '');
console.log('x: ', x);  // x:  99195

क्यों?:

एक और एकमात्र कारण मैं प्रस्तुत किए गए कई अन्य समाधानों के बजाय इसका उपयोग करने के बारे में सोच सकता हूं यदि आप अपने एल्गोरिथ्म के लिए एक कार्यात्मक प्रोग्रामिंग पद्धति को बनाए रखना चाहते हैं, और आप इसे पूरा करने के लिए सबसे अधिक घोषणात्मक दृष्टिकोण चाहते हैं। यदि आपका पूरा लक्ष्य वस्तुतः एक सरणी को वैकल्पिक नॉन-फ़ॉसी प्रिमिटिव (स्ट्रिंग, संख्या, बूलियन, सिंबल) से कम करना है, तो मैं इस आईएस को वास्तव में सबसे अच्छा तरीका मानूंगा।

क्यों नहीं?

एक खराब अभ्यास के रूप में फ़ंक्शन मापदंडों को म्यूट नहीं करने के लिए तर्कों की एक पूरी सूची है।


3
+1। यह स्वीकृत उत्तर होना चाहिए। और फिर भी इस समाधान का उपयोग कभी नहीं किया जाना चाहिए, "क्यों नहीं" के तहत कहा गया है।
जॉन्डोडो

3
यह वास्तव में BAD ADVICE है, क्योंकि spliceएक दृश्य उत्परिवर्तन ( array) करता है। कार्यात्मक प्रतिमान के अनुसार, आप या तो निरंतरता की शैली में कमी का उपयोग करेंगे या एक सही-सहयोगी कम के साथ आलसी मूल्यांकन का उपयोग करेंगे। या, एक सरल विकल्प के रूप में, बस सादा पुनरावृत्ति।

रुको! कम फ़ंक्शन के 4 वें तर्क को म्यूट करके: "सरणी" एक सही कथन नहीं है। इस मामले में यह हो रहा है (उत्तर में उदाहरण) क्योंकि इसकी कटिंग एकल लंबाई सरणी (पहला तत्व) के लिए है, जबकि इसकी पहले से ही सूचकांक 2 तक पहुंच गई है , जाहिर है अगली बार, सूचकांक 3 के लिए इसे आइटम नहीं मिलेगा (जैसे आप 1 की लंबाई के मूल संदर्भ को बदल रहे हैं )। मामले में आप एक पॉप करते हैं जो स्रोत सरणी को भी बदल देगा, लेकिन बीच में नहीं रोकें (यदि आप दूसरे अंतिम सूचकांक में नहीं हैं)।
कौशिक चटर्जी 16

@KoushikChatterjee मेरा कथन मेरे निहित अर्थ के लिए सही है। यह आपके स्पष्ट अर्थ के लिए सही नहीं है। आपको अपने बिंदुओं को शामिल करने के लिए कथन को संशोधित करने पर एक सुझाव देना चाहिए और मैं इसे संपादित कर दूंगा क्योंकि इससे समग्र उत्तर में सुधार होगा।
तोबिया रेक्स

1
मैं किसी भी अवांछित उत्परिवर्तन से बचने के लिए प्रसार ऑपरेटर तक पहुंचना पसंद करता हूं, [... सरणी] .reduce ()
eballeste

16

कम उपयोग न करें। सामान्य पुनरावृत्तियों (जैसे, आदि) के साथ सरणी पर केवल पुनरावृत्त करें और जब आपकी स्थिति पूरी हो जाए, तो उसे तोड़ दें।


58
इसमें मज़ा कहाँ है? :)
अलेक्जेंडर मिल्स

2
@AlexanderMills शायद वह एक एम्पायर बनना पसंद करती है!
डिंम्पायक्स

3
इस जवाब का यहाँ 0 मान है
फेडेहे

यह सुनिश्चित नहीं है कि यह कुछ कई अपवॉट्स है ... यह एक गैर जवाब है क्योंकि ओपी ने पूछा कि कैसे कम करने से जल्दी टूटने के लिए () .. यह एक डॉक्टर के पास जाने की तरह है जब आपको झुकने पर कुछ दर्द होता है और डॉक्टर बताता है तुम झुकना नहीं है।
ricosrealm

12

जब तक आप रिटर्न वैल्यू की परवाह नहीं करते तब तक आप कुछ और हर तरह के कार्यों का उपयोग कर सकते हैं । हर टूट जाता है जब कॉलबैक झूठी देता है, कुछ जब यह सच रिटर्न:

things.every(function(v, i, o) {
  // do stuff 
  if (timeToBreak) {
    return false;
  } else {
    return true;
  }
}, thisArg);

25
लेकिन अगर वह करने की कोशिश कर रहा है reduceतो परिभाषा के अनुसार वह रिटर्न वैल्यू की परवाह करता है।

1
@ torazaburo- यकीन है, लेकिन मैं इसे ओपी में इस्तेमाल नहीं किया जा रहा है और वहाँ एक परिणाम प्राप्त करने के अन्य तरीके हैं। ;-)
रोबग

6

निश्चित रूप से, reduceसमय से पहले बाहर निकलने के लिए अंतर्निहित संस्करण प्राप्त करने का कोई तरीका नहीं है ।

लेकिन आप अपने स्वयं के संस्करण को कम कर सकते हैं जो एक विशेष टोकन का उपयोग करता है ताकि यह पता लगाया जा सके कि लूप कब टूटना चाहिए।

var EXIT_REDUCE = {};

function reduce(a, f, result) {
  for (let i = 0; i < a.length; i++) {
    let val = f(result, a[i], i, a);
    if (val === EXIT_REDUCE) break;
    result = val;
  }
  return result;
}

सरणी का योग करने के लिए इसका उपयोग करें, लेकिन जब आप 99 से बाहर निकलें तो बाहर निकलें:

reduce([1, 2, 99, 3], (a, b) => b === 99 ? EXIT_REDUCE : a + b, 0);

> 3

1
आप वांछित व्यवहार को प्राप्त करने के लिए आलसी मूल्यांकन या सीपीएस का उपयोग कर सकते हैं :
स्क्रिप्टम

इस उत्तर का पहला वाक्य गलत है। आप तोड़ सकते हैं, विवरण के लिए नीचे मेरा उत्तर देखें।
तोबियाह रेक्स

4

Array.every उच्च क्रम पुनरावृत्ति से बाहर तोड़ने के लिए एक बहुत ही प्राकृतिक तंत्र प्रदान कर सकता है।

const product = function(array) {
    let accumulator = 1;
    array.every( factor => {
        accumulator *= factor;
        return !!factor;
    });
    return accumulator;
}
console.log(product([2,2,2,0,2,2]));
// 0


1

आप प्रत्येक कोड को तोड़ सकते हैं - और इस प्रकार इट्रेटर में प्रत्येक निर्माण - एक अपवाद फेंककर:

function breakReduceException(value) {
    this.value = value
}

try {
    Things.reduce(function(memo, current) {
        ...
        if (current <= 0) throw new breakReduceException(memo)
        ...
    }, 0)
} catch (e) {
    if (e instanceof breakReduceException) var memo = e.value
    else throw e
}

6
यह संभवतः सभी उत्तरों का सबसे कम कुशल निष्पादन-वार है। मौजूदा निष्पादन संदर्भ को तोड़ने / पकड़ने की कोशिश करें और निष्पादन के 'धीमे पथ' पर वापस आ जाता है। किसी भी अनुकूलन को अलविदा कहें जो V8 कवर के तहत करता है।
इवान प्लाइस

5
अति नहीं। इसके बारे में कैसे:if (current <= 0) window.top.close()
user56reinstatemonica8

0

जैसा कि promises resolveऔर rejectकॉलबैक तर्क हैं, मैंने कॉलबैक तर्क के reduceसाथ वर्कअराउंड फ़ंक्शन बनाया break। यह मूल reduceविधि के रूप में सभी समान तर्क लेता है , पहले वाले को छोड़कर काम करने के लिए एक सरणी है (बंदर पैचिंग से बचें)। तीसरा [2] initialValueतर्क वैकल्पिक है। functionReducer के लिए नीचे स्निपेट देखें ।

var list = ["w","o","r","l","d"," ","p","i","e","r","o","g","i"];

var result = reducer(list,(total,current,index,arr,stop)=>{
  if(current === " ") stop(); //when called, the loop breaks
  return total + current;
},'hello ');

console.log(result); //hello world

function reducer(arr, callback, initial) {
  var hasInitial = arguments.length >= 3;
  var total = hasInitial ? initial : arr[0];
  var breakNow = false;
  for (var i = hasInitial ? 0 : 1; i < arr.length; i++) {
    var currentValue = arr[i];
    var currentIndex = i;
    var newTotal = callback(total, currentValue, currentIndex, arr, () => breakNow = true);
    if (breakNow) break;
    total = newTotal;
  }
  return total;
}

और यहाँ reducerएक Array methodसंशोधित स्क्रिप्ट है:

Array.prototype.reducer = function(callback,initial){
  var hasInitial = arguments.length >= 2;
  var total = hasInitial ? initial : this[0];
  var breakNow = false;
  for (var i = hasInitial ? 0 : 1; i < this.length; i++) {
    var currentValue = this[i];
    var currentIndex = i;
    var newTotal = callback(total, currentValue, currentIndex, this, () => breakNow = true);
    if (breakNow) break;
    total = newTotal;
  }
  return total;
};

var list = ["w","o","r","l","d"," ","p","i","e","r","o","g","i"];

var result = list.reducer((total,current,index,arr,stop)=>{
  if(current === " ") stop(); //when called, the loop breaks
  return total + current;
},'hello ');


console.log(result);

0

ब्रेक के साथ कार्यात्मक संस्करण को कम करके 'परिवर्तन', पूर्व के रूप में लागू किया जा सकता है। अंडरस्कोर में।

मैंने इसे रोकने के लिए इसे एक कॉन्फिगरेशन फ्लैग के साथ लागू करने की कोशिश की ताकि कार्यान्वयन कम करने के लिए उस डेटा संरचना को बदलना न पड़े जिसे आप वर्तमान में उपयोग कर रहे हैं।

const transform = (arr, reduce, init, config = {}) => {
  const result = arr.reduce((acc, item, i, arr) => {
    if (acc.found) return acc

    acc.value = reduce(config, acc.value, item, i, arr)

    if (config.stop) {
      acc.found = true
    }

    return acc
  }, { value: init, found: false })

  return result.value
}

module.exports = transform

उपयोग 1, सरल

const a = [0, 1, 1, 3, 1]

console.log(transform(a, (config, acc, v) => {
  if (v === 3) { config.stop = true }
  if (v === 1) return ++acc
  return acc
}, 0))

उपयोग 2, कॉन्फ़िगर का उपयोग आंतरिक चर के रूप में करें

const pixes = Array(size).fill(0)
const pixProcessed = pixes.map((_, pixId) => {
  return transform(pics, (config, _, pic) => {
    if (pic[pixId] !== '2') config.stop = true 
    return pic[pixId]
  }, '0')
})

उपयोग 3, बाहरी चर के रूप में कॉन्फिगर कैप्चर करें

const thrusts2 = permute([9, 8, 7, 6, 5]).map(signals => {
  const datas = new Array(5).fill(_data())
  const ps = new Array(5).fill(0)

  let thrust = 0, config
  do {

    config = {}
    thrust = transform(signals, (_config, acc, signal, i) => {
      const res = intcode(
        datas[i], signal,
        { once: true, i: ps[i], prev: acc }
      )

      if (res) {
        [ps[i], acc] = res 
      } else {
        _config.stop = true
      }

      return acc
    }, thrust, config)

  } while (!config.stop)

  return thrust
}, 0)

0

आप एक reduceविधि के अंदर से नहीं तोड़ सकते । इस बात पर निर्भर करते हुए कि आप जो पूरा करने की कोशिश कर रहे हैं वह अंतिम परिणाम को बदल सकता है (जो एक कारण है कि आप ऐसा करना चाहते हैं)

const result = [1, 1, 1].reduce((a, b) => a + b, 0); // returns 3

console.log(result);

const result = [1, 1, 1].reduce((a, b, c, d) => {
  if (c === 1 && b < 3) {
    return a + b + 1;
  } 
  return a + b;
}, 0); // now returns 4

console.log(result);

ध्यान रखें: आप सीधे सरणी पैरामीटर को पुन: असाइन नहीं कर सकते

const result = [1, 1, 1].reduce( (a, b, c, d) => {
  if (c === 0) {
    d = [1, 1, 2];
  } 
  return a + b;
}, 0); // still returns 3

console.log(result);

हालांकि (जैसा कि नीचे बताया गया है), आप सरणी की सामग्री को बदलकर परिणाम को प्रभावित कर सकते हैं:

const result = [1, 1, 1].reduce( (a, b, c, d) => {
  if (c === 0) {
    d[2] = 100;
  } 
  return a + b;
}, 0); // now returns 102

console.log(result);


1
पुनः " आप तर्क मानों को सीधे इस तरह से परिवर्तित नहीं कर सकते हैं जो बाद की गणनाओं को प्रभावित करता है ", यह सच नहीं है। ECMA-262 कहता है: यदि सरणी के मौजूदा तत्वों को बदल दिया जाता है, तो कॉलबैकफ़न के लिए दिया गया उनका मान उस समय का मान होगा, जब वे उनसे मिलने जाते हैं । आपका उदाहरण काम नहीं करता है क्योंकि आप d को एक नया मान दे रहे हैं , मूल सरणी को संशोधित नहीं कर रहे हैं । के d = [1, 1, 2]साथ बदलें d[2] = 6और देखें कि क्या होता है। ;-)
रॉबग

-1

एक और सरल कार्यान्वयन जो मैं एक ही मुद्दे को सुलझाने के साथ आया था:

function reduce(array, reducer, first) {
  let result = first || array.shift()

  while (array.length > 0) {
    result = reducer(result, array.shift())
    if (result && result.reduced) {
      return result.reduced
    }
  }

  return result
}

-1

यदि आप नीचे दिए गए पैटर्न का उपयोग करते हुए क्रमिक रूप से श्रृंखलाओं का वादा करना चाहते हैं:

return [1,2,3,4].reduce(function(promise,n,i,arr){
   return promise.then(function(){
       // this code is executed when the reduce loop is terminated,
       // so truncating arr here or in the call below does not works
       return somethingReturningAPromise(n);
   });
}, Promise.resolve());

लेकिन किसी वादे के अंदर या बाहर हो रही चीज़ों के अनुसार तोड़ने की ज़रूरत है, चीजें थोड़ी अधिक जटिल हो जाती हैं क्योंकि पहले वादे को पूरा करने से पहले कम लूप को समाप्त कर दिया जाता है, जिससे वादे में आ रही तल्खी बेकार हो जाती है, मैं इस कार्यान्वयन के साथ समाप्त हो गया।

function reduce(array, promise, fn, i) {
  i=i||0;
  return promise
  .then(function(){
    return fn(promise,array[i]);
  })
  .then(function(result){
    if (!promise.break && ++i<array.length) {
      return reduce(array,promise,fn,i);
    } else {
      return result;
    }
  })
}

तो आप इस तरह से कुछ कर सकते हैं:

var promise=Promise.resolve();
reduce([1,2,3,4],promise,function(promise,val){
  return iter(promise, val);
}).catch(console.error);

function iter(promise, val) {
  return new Promise(function(resolve, reject){
    setTimeout(function(){
      if (promise.break) return reject('break');
      console.log(val);
      if (val==3) {promise.break=true;}
      resolve(val);
    }, 4000-1000*val);
  });
}

-1

मैंने इसे इस प्रकार हल किया, उदाहरण के लिए उस someविधि में, जहाँ लघु परिचलन बहुत बचत कर सकता है:

const someShort = (list, fn) => {
  let t;
  try {
    return list.reduce((acc, el) => {
      t = fn(el);
      console.log('found ?', el, t)
      if (t) {
        throw ''
      }
      return t
    }, false)
  } catch (e) {
    return t
  }
}

const someEven = someShort([1, 2, 3, 1, 5], el => el % 2 === 0)

console.log(someEven)

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