क्या उत्परिवर्तनीय चर के बिना ES6 (ECMAScript 6) में x बार लूप करने की व्यवस्था है?


157

xजावास्क्रिप्ट में लूप समय का विशिष्ट तरीका है:

for (var i = 0; i < x; i++)
  doStuff(i);

लेकिन मैं ++ऑपरेटर का उपयोग नहीं करना चाहता या उसके पास कोई भी परिवर्तनशील चर नहीं है। तो वहाँ एक रास्ता है, ES6 में, xएक और तरीका लूप करने के लिए? मुझे रूबी का तंत्र बहुत पसंद है:

x.times do |i|
  do_stuff(i)
end

जावास्क्रिप्ट में कुछ भी इसी तरह / ES6? मैं एक तरह का धोखा दे सकता था और अपना खुद का जनरेटर बना सकता था:

function* times(x) {
  for (var i = 0; i < x; i++)
    yield i;
}

for (var i of times(5)) {
  console.log(i);
}

बेशक मैं अभी भी उपयोग कर रहा हूँ i++। कम से कम यह दृष्टि से बाहर है :), लेकिन मुझे उम्मीद है कि ES6 में एक बेहतर तंत्र है।


3
परिवर्तनशील लूप नियंत्रण चर एक समस्या क्यों है? सिर्फ एक सिद्धांत?
doldt

1
@doldt - मैं जावास्क्रिप्ट को पढ़ाने के लिए कोशिश कर रहा हूँ, लेकिन मैं बाद में जब तक अस्थायी चर की अवधारणा में देरी के साथ प्रयोग कर रहा हूँ
पर।

5
हम यहां वास्तव में ऑफ-टॉपिक हो रहे हैं, लेकिन क्या आप सुनिश्चित हैं कि ईएस 6 जनरेटर (या किसी अन्य नए, उच्च स्तर की अवधारणा) पर आगे बढ़ना एक अच्छा विचार है, इससे पहले कि वे परिवर्तनशील चरों के बारे में जानें? :)
doldt

5
@ डॉल्ड्ट - शायद, मैं प्रयोग कर रहा हूं। जावास्क्रिप्ट के लिए एक कार्यात्मक भाषा दृष्टिकोण लेना।
पर।

लूप में उस वेरिएबल को घोषित करने के लिए उपयोग करें। इसका दायरा लूप के साथ समाप्त होता है।
ncmathsadist

जवाबों:


156

ठीक है!

नीचे दिए गए कोड को ES6 सिंटैक्स का उपयोग करके लिखा गया है लेकिन आसानी से ES5 या उससे भी कम में लिखा जा सकता है। ES6 "लूप x बार तंत्र" बनाने की आवश्यकता नहीं है


यदि आपको कॉलबैक में पुनरावृत्त की आवश्यकता नहीं है , तो यह सबसे सरल कार्यान्वयन है

const times = x => f => {
  if (x > 0) {
    f()
    times (x - 1) (f)
  }
}

// use it
times (3) (() => console.log('hi'))

// or define intermediate functions for reuse
let twice = times (2)

// twice the power !
twice (() => console.log('double vision'))

यदि आपको पुनरावृत्ति की आवश्यकता है, तो आप अपने लिए पुनरावृति करने के लिए काउंटर पैरामीटर के साथ नामित आंतरिक फ़ंक्शन का उपयोग कर सकते हैं

const times = n => f => {
  let iter = i => {
    if (i === n) return
    f (i)
    iter (i + 1)
  }
  return iter (0)
}

times (3) (i => console.log(i, 'hi'))


अगर आपको और चीजें सीखना पसंद नहीं है तो यहां पढ़ना बंद कर दें ...

लेकिन उन लोगों के बारे में कुछ महसूस करना चाहिए ...

  • एकल शाखा ifविवरण बदसूरत हैं - दूसरी शाखा पर क्या होता है?
  • कार्य निकायों में कई कथन / भाव - क्या प्रक्रिया संबंधी चिंताएं मिश्रित हो रही हैं?
  • निहित रूप से undefined- अशुद्ध, साइड-इफेक्टिंग फ़ंक्शन का संकेत

"क्या कोई बेहतर तरीका नहीं है?"

वहाँ है। आइए पहले हमारे प्रारंभिक कार्यान्वयन पर फिर से विचार करें

// times :: Int -> (void -> void) -> void
const times = x => f => {
  if (x > 0) {
    f()               // has to be side-effecting function
    times (x - 1) (f)
  }
}

ज़रूर, यह सरल है, लेकिन ध्यान दें कि हम कैसे कॉल f()करते हैं और इसके साथ कुछ भी नहीं करते हैं। यह वास्तव में फ़ंक्शन के प्रकार को सीमित करता है जिसे हम कई बार दोहरा सकते हैं। यहां तक ​​कि अगर हमारे पास यह उपलब्ध है, f(i)तो अधिक बहुमुखी नहीं है।

क्या होगा अगर हम एक बेहतर प्रकार के फ़ंक्शन पुनरावृत्ति प्रक्रिया के साथ शुरू करते हैं? शायद कुछ ऐसा जो इनपुट और आउटपुट का बेहतर उपयोग करता है।

सामान्य कार्य पुनरावृत्ति

// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
  if (n > 0)
    return repeat (n - 1) (f) (f (x))
  else
    return x
}

// power :: Int -> Int -> Int
const power = base => exp => {
  // repeat <exp> times, <base> * <x>, starting with 1
  return repeat (exp) (x => base * x) (1)
}

console.log(power (2) (8))
// => 256

ऊपर, हमने एक सामान्य repeatफ़ंक्शन को परिभाषित किया है जो एक अतिरिक्त इनपुट लेता है जिसका उपयोग किसी एकल फ़ंक्शन के दोहराए गए एप्लिकेशन को शुरू करने के लिए किया जाता है।

// repeat 3 times, the function f, starting with x ...
var result = repeat (3) (f) (x)

// is the same as ...
var result = f(f(f(x)))

के timesसाथ कार्यान्वित कर रहा हैrepeat

खैर अब यह आसान है; लगभग सभी काम पहले ही हो चुके हैं।

// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
  if (n > 0)
    return repeat (n - 1) (f) (f (x))
  else
    return x
}

// times :: Int -> (Int -> Int) -> Int 
const times = n=> f=>
  repeat (n) (i => (f(i), i + 1)) (0)

// use it
times (3) (i => console.log(i, 'hi'))

चूंकि हमारा फ़ंक्शन iएक इनपुट के रूप में लेता है और रिटर्न i + 1करता है, इसलिए यह प्रभावी रूप से हमारे पुनरावृत्त के रूप में काम करता है जिसे हम fहर बार पास करते हैं।

हमने मुद्दों की अपनी बुलेट सूची भी तय कर दी है

  • कोई और अधिक बदसूरत एकल शाखा ifबयान नहीं
  • एकल-अभिव्यक्ति निकाय अच्छी तरह से अलग चिंताओं का संकेत देते हैं
  • अधिक बेकार नहीं, स्पष्ट रूप से वापस आ गया undefined

जावास्क्रिप्ट अल्पविराम ऑपरेटर,

मामले में आपको यह देखने में परेशानी हो रही है कि अंतिम उदाहरण कैसे काम कर रहा है, यह जावास्क्रिप्ट के सबसे पुराने युद्ध कुल्हाड़ियों में से एक की आपकी जागरूकता पर निर्भर करता है; अल्पविराम ऑपरेटर - संक्षेप में, यह भाव बाएं से दाएं मूल्यांकन करता है और रिटर्न पिछले का मूल्यांकन अभिव्यक्ति के मूल्य

(expr1 :: a, expr2 :: b, expr3 :: c) :: c

हमारे उपरोक्त उदाहरण में, मैं उपयोग कर रहा हूं

(i => (f(i), i + 1))

जो लेखन का एक मात्र तरीका है

(i => { f(i); return i + 1 })

टेल कॉल ऑप्टिमाइज़ेशन

जैसा कि पुनरावर्ती कार्यान्वयन के रूप में सेक्सी हैं, इस बिंदु पर मेरे लिए यह सलाह देना गैरजिम्मेदार होगा कि कोई भी जावास्क्रिप्ट वीएम मैं उचित पूंछ कॉल उन्मूलन का समर्थन करने के बारे में नहीं सोच सकता - बेबल इसे ट्रांसपाइल करता था, लेकिन यह "टूटी हुई" में फिर से लागू होगा। "एक वर्ष से अधिक के लिए स्थिति।

repeat (1e6) (someFunc) (x)
// => RangeError: Maximum call stack size exceeded

जैसे, हमें repeatइसे स्टैक-सेफ बनाने के लिए अपने कार्यान्वयन पर फिर से विचार करना चाहिए ।

नीचे दिया गया कोड उत्परिवर्तनीय चर का उपयोग करता हैn और xध्यान दें कि सभी उत्परिवर्तन repeatफ़ंक्शन में स्थानीय हैं - कोई भी राज्य परिवर्तन (म्यूटेशन) फ़ंक्शन के बाहर से दिखाई नहीं देता है

// repeat :: Int -> (a -> a) -> (a -> a)
const repeat = n => f => x =>
  {
    let m = 0, acc = x
    while (m < n)
      (m = m + 1, acc = f (acc))
    return acc
  }

// inc :: Int -> Int
const inc = x =>
  x + 1

console.log (repeat (1e8) (inc) (0))
// 100000000

यह आपको बहुत कुछ कह रहा है "लेकिन यह कार्यात्मक नहीं है!" - मुझे पता है, बस आराम करो। हम शुद्ध भावों का उपयोग करते हुए निरंतर-स्पेस लूपिंग के लिए क्लोजर-स्टाइल loop/ recurइंटरफ़ेस लागू कर सकते हैं ; उस सामान में से कोई भी नहीं ।while

यहां हम whileअपने loopफ़ंक्शन के साथ सार करते हैं - यह recurलूप को चालू रखने के लिए एक विशेष प्रकार की तलाश करता है। जब एक गैर- recurप्रकार का सामना किया जाता है, तो लूप समाप्त हो जाता है और गणना का परिणाम वापस आ जाता है

const recur = (...args) =>
  ({ type: recur, args })
  
const loop = f =>
  {
    let acc = f ()
    while (acc.type === recur)
      acc = f (...acc.args)
    return acc
  }

const repeat = $n => f => x =>
  loop ((n = $n, acc = x) =>
    n === 0
      ? acc
      : recur (n - 1, f (acc)))
      
const inc = x =>
  x + 1

const fibonacci = $n =>
  loop ((n = $n, a = 0, b = 1) =>
    n === 0
      ? a
      : recur (n - 1, b, a + b))
      
console.log (repeat (1e7) (inc) (0)) // 10000000
console.log (fibonacci (100))        // 354224848179262000000


24
अधिरोपित लगता है (मैं विशेष रूप से उलझन में हूँ g => g(g)(x))। क्या पहले-क्रम वाले एक से अधिक उच्च-कार्य फ़ंक्शन से लाभ है, जैसे मेरे समाधान में?
पावलो

1
@naomik: लिंक पोस्ट करने के लिए समय निकालने के लिए धन्यवाद। बहुत सराहना की।
Pineda

1
@ AlfonsoPérez मैं टिप्पणी की सराहना करता हूं। मैं देखूंगा कि क्या मैं वहां कहीं थोड़ा हिंट काम कर सकता हूं ^ _ ^
धन्यवाद

1
@naomik विदाई TCO ! मेरा सबकुछ उजड़ गया।

10
ऐसा लगता है कि यह उत्तर स्वीकार किया गया है और अच्छी तरह से मूल्यांकन किया गया है क्योंकि इसमें बहुत प्रयास किए गए होंगे, लेकिन मुझे नहीं लगता कि यह एक अच्छा उत्तर है। प्रश्न का सही उत्तर "नहीं" है। आपके द्वारा किए गए वर्कअराउंड को सूचीबद्ध करना सहायक है, लेकिन इसके ठीक बाद आप कहते हैं कि एक बेहतर तरीका है। आप केवल उस उत्तर को क्यों नहीं डालते हैं और सबसे ऊपर वाले को हटा देते हैं? आप कॉमा ऑपरेटरों को क्यों समझा रहे हैं? आप क्लोजर को क्यों लाते हैं? सामान्य तौर पर, 2 वर्ण उत्तर वाले प्रश्न के लिए इतने सारे स्पर्श क्यों? कुछ साफ-सुथरे प्रोग्रामिंग तथ्यों पर प्रस्तुति देने के लिए सरल प्रश्न उपयोगकर्ताओं के लिए सिर्फ एक मंच नहीं है।
टिमोफी 'साशा' कोंद्रशोव

266

ES2015 स्प्रेड ऑपरेटर का उपयोग करना :

[...Array(n)].map()

const res = [...Array(10)].map((_, i) => {
  return i * 10;
});

// as a one liner
const res = [...Array(10)].map((_, i) => i * 10);

या यदि आपको परिणाम की आवश्यकता नहीं है:

[...Array(10)].forEach((_, i) => {
  console.log(i);
});

// as a one liner
[...Array(10)].forEach((_, i) => console.log(i));

या ES2015 Array.from ऑपरेटर का उपयोग कर :

Array.from(...)

const res = Array.from(Array(10)).map((_, i) => {
  return i * 10;
});

// as a one liner
const res = Array.from(Array(10)).map((_, i) => i * 10);

ध्यान दें कि यदि आपको बार-बार स्ट्रिंग की आवश्यकता है तो आप String.prototype.repeat का उपयोग कर सकते हैं ।

console.log("0".repeat(10))
// 0000000000

26
बेहतर:Array.from(Array(10), (_, i) => i*10)
बरगी

6
यह सबसे अच्छा जवाब होना चाहिए। तो ES6! बहुत कमाल!
गेरहली फेहरिवा

3
यदि आपको पुनरावृत्ति (i) की आवश्यकता नहीं है, तो आप इसे बनाने के लिए कुंजी और मान दोनों को बाहर कर सकते हैं:[...Array(10)].forEach(() => console.log('looping 10 times');
Sterling Bourne

9
तो आप इसे फेंकने के लिए एन तत्वों के पूरे सरणी को आवंटित करते हैं?
कुगेल

2
क्या किसी ने कुगेल की पिछली टिप्पणी को संबोधित किया है? मैं एक ही बात सोच रहा था
अरमान

37
for (let i of Array(100).keys()) {
    console.log(i)
}

यह काम करता है, इसलिए यह बहुत अच्छा है! लेकिन इस अर्थ में थोड़ा बदसूरत है कि अतिरिक्त काम की आवश्यकता है और यह वह नहीं है जिसके लिए Arrayकुंजियों का उपयोग किया जाता है।
पर।

@at। वास्तव में। लेकिन मुझे यकीन नहीं है कि [0..x]जेएस के लिए एक हेकेल का पर्यायवाची है जो मेरे उत्तर की तुलना में अधिक संक्षिप्त है।
झटके

आप सही हो सकते हैं कि इससे अधिक संक्षिप्त कुछ भी नहीं है।
पर।

ठीक है, मैं समझता हूँ कि क्यों यह काम करता है के बीच मतभेद को देखते हुए Array.prototype.keysऔर Object.prototype.keys, लेकिन यह सुनिश्चित शुरुआत में भ्रमित कर रहा है।
मार्क रीड

1
ES2015 में TCO के साथ @cchamberlain (हालांकि कहीं भी लागू नहीं?) यह चिंता का कम हो सकता है, लेकिन वास्तव में :-)
zerkms 21

29

मुझे लगता है कि सबसे अच्छा समाधान का उपयोग करना है let:

for (let i=0; i<100; i++) 

यह iप्रत्येक शरीर के मूल्यांकन के लिए एक नया (उत्परिवर्तित) वैरिएबल बनाएगा और आश्वस्त करेगा कि iयह केवल उस लूप सिंटैक्स में वृद्धि की अभिव्यक्ति में बदला गया है, कहीं और से नहीं।

मैं एक तरह का धोखा दे सकता था और अपना खुद का जनरेटर बना सकता था। कम से कम i++दृष्टि से बाहर है :)

वह पर्याप्त इमो होना चाहिए। यहां तक ​​कि शुद्ध भाषाओं में भी सभी ऑपरेशन (या कम से कम, उनके दुभाषिए) आदिम से निर्मित होते हैं जो उत्परिवर्तन का उपयोग करते हैं। जब तक यह ठीक से स्कोप है, मैं नहीं देख सकता कि इसके साथ क्या गलत है।

आप के साथ ठीक होना चाहिए

function* times(n) {
  for (let i = 0; i < x; i++)
    yield i;
}
for (const i of times(5))
  console.log(i);

लेकिन मैं ++ऑपरेटर का उपयोग नहीं करना चाहता या उसके पास कोई भी परिवर्तनशील चर नहीं है।

फिर आपकी एकमात्र पसंद पुनरावर्तन का उपयोग करना है। आप एक उत्परिवर्ती के बिना भी उस जनरेटर फ़ंक्शन को परिभाषित कर सकते हैं i:

function* range(i, n) {
  if (i >= n) return;
  yield i;
  return yield* range(i+1, n);
}
times = (n) => range(0, n);

लेकिन ऐसा लगता है कि मुझे ओवरकिल हो गया है और प्रदर्शन की समस्या हो सकती है (जैसा कि टेल कॉल एलिमिनेशन उपलब्ध नहीं है return yield*)।


1
मुझे यह विकल्प पसंद है - अच्छा और सरल!
DanV

2
यह सरल और बिंदु है और ऊपर कई उत्तरों की तरह एक सरणी आवंटित नहीं करता है
Kugel

@Kugel दूसरा स्टैक पर आवंटित हो सकता है, हालांकि
बरगी

अच्छी बात यह सुनिश्चित नहीं है कि अगर टेल-कॉल ऑप्टिमाइज़ेशन यहाँ काम करेगा @Bergi
Kugel

13
const times = 4;
new Array(times).fill().map(() => console.log('test'));

यह स्निपेट console.log test4 बार होगा ।


Whats भरने के लिए समर्थन?
आमिर अफरीदी

2
@AamirAfridi आप ब्राउज़र संगतता अनुभाग की जांच कर सकते हैं, वहाँ भी है प्रदान की एक polyfill: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Hossam मोराद


11

उत्तर: 09 दिसंबर 2015

व्यक्तिगत रूप से, मुझे संक्षिप्त (अच्छा) और छंद (बुरा) दोनों का स्वीकृत उत्तर मिला। इस कथन की सराहना करना व्यक्तिपरक हो सकता है, इसलिए कृपया इस उत्तर को पढ़ें और देखें कि क्या आप सहमत हैं या असहमत हैं

प्रश्न में दिया गया उदाहरण कुछ इस तरह था रूबी का:

x.times do |i|
  do_stuff(i)
end

नीचे का उपयोग करके जेएस में इसे व्यक्त करने की अनुमति होगी:

times(x)(doStuff(i));

यहाँ कोड है:

let times = (n) => {
  return (f) => {
    Array(n).fill().map((_, i) => f(i));
  };
};

बस!

सरल उदाहरण उपयोग:

let cheer = () => console.log('Hip hip hooray!');

times(3)(cheer);

//Hip hip hooray!
//Hip hip hooray!
//Hip hip hooray!

वैकल्पिक रूप से, स्वीकृत उत्तर के उदाहरणों का अनुसरण करते हुए:

let doStuff = (i) => console.log(i, ' hi'),
  once = times(1),
  twice = times(2),
  thrice = times(3);

once(doStuff);
//0 ' hi'

twice(doStuff);
//0 ' hi'
//1 ' hi'

thrice(doStuff);
//0 ' hi'
//1 ' hi'
//2 ' hi'

साइड नोट - एक रेंज फ़ंक्शन को परिभाषित करना

एक समान / संबंधित प्रश्न, जो मौलिक रूप से बहुत समान कोड निर्माण का उपयोग करता है, हो सकता है कि इसमें (कोर) जावास्क्रिप्ट में एक सुविधाजनक रेंज फ़ंक्शन है, जो अंडरस्कोर के रेंज फ़ंक्शन के समान है।

X से शुरू होकर, n संख्याओं के साथ एक सरणी बनाएं

अंडरस्कोर

_.range(x, x + n)

ES2015

विकल्प के जोड़े:

Array(n).fill().map((_, i) => x + i)

Array.from(Array(n), (_, i) => x + i)

N = 10, x = 1 का उपयोग करके डेमो:

> Array(10).fill().map((_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

> Array.from(Array(10), (_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

एक त्वरित परीक्षण में, मैं भाग गया, जिसमें से प्रत्येक ने हमारे समाधान और doStuff फ़ंक्शन का उपयोग करके प्रत्येक को एक लाख बार चलाया, पूर्व दृष्टिकोण (Array (n) .fill ()) थोड़ा तेज साबित हुआ।


8
Array(100).fill().map((_,i)=> console.log(i) );

यह संस्करण अपरिवर्तनीयता के लिए ओपी की आवश्यकता को पूरा करता है। इसके अलावा अपने उपयोग के मामले reduceके mapआधार पर उपयोग करने पर विचार करें।

यह भी एक विकल्प है अगर आपको अपने प्रोटोटाइप में थोड़ा सा भी बदलाव नहीं आता है।

Number.prototype.times = function(f) {
   return Array(this.valueOf()).fill().map((_,i)=>f(i));
};

अब हम ऐसा कर सकते हैं

((3).times(i=>console.log(i)));

.fillसुझाव के लिए आर्कसेलडॉन के लिए +1 ।


IE या ओपेरा या फैंटमोज़ में समर्थित विधि के रूप में वोट नहीं किया गया
15

8

यहाँ एक और अच्छा विकल्प है:

Array.from({ length: 3}).map(...);

अधिमानतः, जैसा कि @Dave Morse ने टिप्पणी में बताया है, आप फ़ंक्शन mapके दूसरे पैरामीटर का उपयोग करके भी कॉल से छुटकारा पा सकते हैं Array.from:

Array.from({ length: 3 }, () => (...))


2
यह स्वीकृत उत्तर होना चाहिए! एक छोटा सुझाव - आपको पहले से ही Array.from के साथ मुफ्त के लिए आवश्यक मानचित्र-जैसी कार्यक्षमता प्राप्त होती है: Array.from({ length: label.length }, (_, i) => (...)) यह मैप के लिए कॉल को बंद करने के लिए खाली अस्थायी सरणी बनाने से बचाता है।
डेव मोर्स

7

ऐसा कुछ नहीं जो मैं सिखाऊंगा (या मेरे कोड में कभी उपयोग करूँगा), लेकिन यहाँ एक कोडगुल्फ़-योग्य समाधान है, जो एक चर को परिवर्तित किए बिना, ES6 की कोई आवश्यकता नहीं है:

Array.apply(null, {length: 10}).forEach(function(_, i){
    doStuff(i);
})

एक उपयोगी जवाब की तुलना में एक दिलचस्प सबूत की अवधारणा की बात, वास्तव में।


Coudn't Array.apply(null, {length: 10})बस हो Array(10)?
पावलो

1
@ पावलो, वास्तव में, नहीं। ऐरे (10) लंबाई की एक सरणी बनाएगी 10, लेकिन इसमें परिभाषित किसी भी कुंजी के बिना, जो इस मामले में पूर्व निर्माण को उपयोग करने योग्य नहीं बनाता है। लेकिन वास्तव में यह सरलीकृत किया जा सकता है यदि आप न केवल उपयोग करते हैं, तो ज़र्कम्स का उत्तर देखें (हालांकि ईएस 6 का उपयोग करता है)।
doldt

रचनात्मक @doldt, लेकिन मैं कुछ मिलनसार और सरल लग रही हूँ।
पर।

5

मुझे पार्टी के लिए देर हो रही है, लेकिन चूंकि यह सवाल अक्सर खोज परिणामों में बदल जाता है, मैं सिर्फ एक समाधान जोड़ना चाहूंगा जिसे मैं लंबे समय तक नहीं रहने के दौरान पठनीयता के मामले में सबसे अच्छा मानता हूं (जो किसी भी कोडबेस आईएमओ के लिए आदर्श है) । यह mutates, लेकिन मैं KISS सिद्धांतों के लिए कि तालमेल बनाने चाहते हैं।

let times = 5
while( times-- )
    console.log(times)
// logs 4, 3, 2, 1, 0

3
इस बात के लिए धन्यवाद कि मैं केवल उच्चतर लंबोदर बुत पार्टी के रूप में वर्णन कर सकता हूं। मैं भी इस Q & A पर समाप्त हो गया, एक सहज-प्रथम-हिट-ऑन-Google-पथ का अनुसरण करते हुए और तेज़ी से यहाँ के अधिकांश उत्तरों से मेरी विवेकहीनता समाप्त हो गई। आपकी सूची में पहला है कि मैं एक सीधी समस्या के लिए एक सीधा समाधान पर विचार करूंगा।
मार्टिन डेविलर्स

केवल इसके साथ समस्या यह है कि यदि आप timesलूप के अंदर चर का उपयोग करना चाहते हैं तो यह थोड़ा उल्टा है । शायद countdownएक बेहतर नामकरण होगा। अन्यथा, पृष्ठ पर सबसे साफ और स्पष्ट उत्तर।
टोनी ब्रजुनस

3

Afaik, रूबी की timesविधि के समान ES6 में कोई तंत्र नहीं है । लेकिन आप पुनरावृत्ति का उपयोग करके उत्परिवर्तन से बच सकते हैं:

let times = (i, cb, l = i) => {
  if (i === 0) return;

  cb(l - i);
  times(i - 1, cb, l);
}

times(5, i => doStuff(i));

डेमो: http://jsbin.com/koyecovano/1/edit?js,console


मुझे यह दृष्टिकोण पसंद है, मुझे पुनरावृत्ति पसंद है। लेकिन मुझे नए जावास्क्रिप्ट उपयोगकर्ताओं को दिखाने के लिए कुछ सरल पसंद आएगा।
पर।

3

यदि आप एक पुस्तकालय का उपयोग करने के लिए तैयार हैं, तो भी लॉश_.times या अंडरस्कोर है_.times :

_.times(x, i => {
   return doStuff(i)
})

ध्यान दें कि यह परिणामों की एक सरणी देता है, इसलिए यह वास्तव में इस रूबी की तरह है:

x.times.map { |i|
  doStuff(i)
}

2

कार्यात्मक प्रतिमान repeatमें आमतौर पर एक अनंत पुनरावर्ती कार्य होता है। इसका उपयोग करने के लिए हमें या तो आलसी मूल्यांकन या निरंतरता शैली की आवश्यकता होती है।

आलसी ने फ़ंक्शन पुनरावृत्ति का मूल्यांकन किया

const repeat = f => x => [x, () => repeat(f) (f(x))];
const take = n => ([x, f]) => n === 0 ? x : take(n - 1) (f());

console.log(
  take(8) (repeat(x => x * 2) (1)) // 256
);

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

निरंतरता गुजर शैली के साथ समारोह दोहराव

const repeat = f => x => [x, k => k(repeat(f) (f(x)))];
const take = n => ([x, k]) => n === 0 ? x : k(take(n - 1));

console.log(
  take(8) (repeat(x => x * 2) (1)) // 256
);

सीपीएस पहली बार में थोड़ा डरावना है। हालांकि, यह हमेशा एक ही पैटर्न का अनुसरण करता है: अंतिम तर्क निरंतरता (एक फ़ंक्शन) है, जो अपने स्वयं के शरीर को आमंत्रित करता है k => k(...):। कृपया ध्यान दें कि सीपीएस अंदर बाहर आवेदन बदल जाता है, यानी take(8) (repeat...)हो जाता है k(take(8)) (...), जहां kआंशिक रूप से लागू किया जाता है repeat

निष्कर्ष

repeatसमाप्ति की स्थिति से पुनरावृत्ति ( ) को अलग करके ( takeहम लचीलापन प्राप्त करते हैं - इसके कड़वे अंत तक चिंताओं को अलग करना: डी।


1

इस घोल के फायदे

  • पढ़ने / उपयोग करने के लिए सबसे सरल (imo)
  • वापसी मूल्य का उपयोग राशि के रूप में किया जा सकता है, या बस अनदेखा किया जा सकता है
  • सादा es6 संस्करण, कोड के टाइपस्क्रिप्ट संस्करण के लिए भी लिंक

नुकसान - उत्परिवर्तन। केवल आंतरिक होने के नाते मुझे परवाह नहीं है, शायद कुछ अन्य लोग भी नहीं करेंगे।

उदाहरण और संहिता

times(5, 3)                       // 15    (3+3+3+3+3)

times(5, (i) => Math.pow(2,i) )   // 31    (1+2+4+8+16)

times(5, '<br/>')                 // <br/><br/><br/><br/><br/>

times(3, (i, count) => {          // name[0], name[1], name[2]
    let n = 'name[' + i + ']'
    if (i < count-1)
        n += ', '
    return n
})

function times(count, callbackOrScalar) {
    let type = typeof callbackOrScalar
    let sum
    if (type === 'number') sum = 0
    else if (type === 'string') sum = ''

    for (let j = 0; j < count; j++) {
        if (type === 'function') {
            const callback = callbackOrScalar
            const result = callback(j, count)
            if (typeof result === 'number' || typeof result === 'string')
                sum = sum === undefined ? result : sum + result
        }
        else if (type === 'number' || type === 'string') {
            const scalar = callbackOrScalar
            sum = sum === undefined ? scalar : sum + scalar
        }
    }
    return sum
}

TypeScipt संस्करण
https://codepen.io/whitneyland/pen/aVjaaE?editors=0011


0

कार्यात्मक पहलू को संबोधित करना:

function times(n, f) {
    var _f = function (f) {
        var i;
        for (i = 0; i < n; i++) {
            f(i);
        }
    };
    return typeof f === 'function' && _f(f) || _f;
}
times(6)(function (v) {
    console.log('in parts: ' + v);
});
times(6, function (v) {
    console.log('complete: ' + v);
});

5
"कार्यात्मक पहलू को संबोधित करना" और फिर एक उत्परिवर्ती के साथ अनिवार्य लूप का उपयोग करना itimesसादे पुराने पर भी उपयोग करने का क्या कारण है for?
झटके

पुन: उपयोग की तरह var twice = times(2);
नीना स्कोल्ज़

तो क्यों न सिर्फ forदो बार उपयोग करें ?
झटके

मैं के लिए उपयोग करने के लिए डर नहीं रहा हूँ। सवाल यह था कि एक वैरिएबल का उपयोग नहीं करना चाहिए। लेकिन परिणाम हमेशा कैशिंग उर्फ ​​चर के कुछ प्रकार है।
नीना स्कोल्ज़

1
"कुछ ऐसा था जो वैरैबेल का उपयोग नहीं करता था" --- और आप अभी भी इसका उपयोग करते हैं - i++। यह स्पष्ट नहीं है कि किसी फ़ंक्शन में अस्वीकार्य कुछ लपेटना कैसे बेहतर बनाता है।
झटके

0

जेनरेटर? प्रत्यावर्तन? इतनी हेटिन atin म्यूटैटिन ’पर क्यों? ;-)

यदि यह स्वीकार्य है कि जब तक हम इसे "छिपा" रहे हैं, तो बस एक गैर-संचालक के उपयोग को स्वीकार करें और हम चीजों को सरल रख सकते हैं :

Number.prototype.times = function(f) { let n=0 ; while(this.valueOf() > n) f(n++) }

जैसे माणिक में:

> (3).times(console.log)
0
1
2

2
अंगूठे ऊपर: "म्यूटैटिन पर इतना हेटिन क्यों?"
सरीफ

1
सादगी के लिए अंगूठे, रूबी-शैली में जाने के लिए अंगूठे बंदर के साथ बहुत अधिक हैं। बस उन बुरे बुरे बंदरों को ना कहें।
मर्म

1
@mrm यह "मंकी पैचिंग" है, क्या यह विस्तार का मामला नहीं है? गले लगाओ और
बढ़ाओ

सं। संख्या (या स्ट्रिंग या एरे या किसी अन्य वर्ग के लिए जो आपने लेखक नहीं किया था) के कार्यों को जोड़ना, परिभाषा के अनुसार, या तो पॉलीफ़िल या बंदर पैच - और यहां तक ​​कि पॉलीफ़िल भी अनुशंसित नहीं हैं। "बंदर पैच", "पॉलीफिल," और एक अनुशंसित विकल्प की परिभाषाएं पढ़ें, "पोनीफिल।" ये वही है जो आप चाहते हो।
MRM

संख्या बढ़ाने के लिए आप क्या करेंगे: वर्ग सुपरनंबर संख्या {बार (fn) {को बढ़ाता है (आइए = = i <i; i ++;) {fn (i); }}}
अलेक्जेंडर

0

मैंने @Tieme के उत्तर को एक सहायक फ़ंक्शन के साथ लपेटा।

टाइपस्क्रिप्ट में:

export const mapN = <T = any[]>(count: number, fn: (...args: any[]) => T): T[] => [...Array(count)].map((_, i) => fn())

अब आप चला सकते हैं:

const arr: string[] = mapN(3, () => 'something')
// returns ['something', 'something', 'something']

0

यह मैंने बनाया है:

function repeat(func, times) {
    for (var i=0; i<times; i++) {
        func(i);
    }
}

उपयोग:

repeat(function(i) {
    console.log("Hello, World! - "+i);
}, 5)

/*
Returns:
Hello, World! - 0
Hello, World! - 1
Hello, World! - 2
Hello, World! - 3
Hello, World! - 4
*/

iउपयोगी अगर आप छवियों के एक एक्स राशि पहले से लोड करने की जरूरत है - चर राशि समय की यह फंस गया हो।

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