अधिक-से-कम / से कम के लिए स्विच स्टेटमेंट


230

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

switch (scrollLeft) {
  case (<1000):
   //do stuff
   break;
  case (>1000 && <2000):
   //do stuff
   break;
}

अब मुझे पता है कि उन बयानों में से कोई भी ( <1000) या ( >1000 && <2000) अलग-अलग कारणों से (स्पष्ट रूप से) काम नहीं करेगा। मैं जो पूछ रहा हूं वह सिर्फ करने का सबसे कुशल तरीका है। मुझे 30 ifकथनों का उपयोग करने से नफरत है , इसलिए मैं स्विच सिंटैक्स का उपयोग करूंगा। क्या ऐसा कुछ है जो मैं कर सकता हूं?


5
क्या आपके कदम नियमित हैं? मेरा मतलब है, यदि आप स्क्रॉललेट को 1000 से विभाजित करते हैं, तो आप 1, 2, 3 को स्विच कर सकते हैं ...
IcanDivideBy0

हो सकता है कि आप एक सॉर्ट किए गए सरणी बना सकते हैं जो इसी ऑपरेशन के साथ एक शर्त सीमा को मैप करता है, और उस पर एक द्विआधारी खोज लागू करता है। या यदि आपकी स्थितियां नियमित रूप से पर्याप्त हैं, तो आप सीधे कॉल कर सकते हैं your_mapper_object[scrollLeft / SOME_CONST], यह मानते हुए your_mapper_objectकि कुछ ऐसा है {1: some_func, 2: another_func, ...}। और इस मामले में आप स्विच का उपयोग भी कर सकते हैं।
जियांग

जवाबों:


731

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

                    क्रोम फ़ायरफ़ॉक्स ओपेरा MSIE सफारी नोड
-------------------------------------------------- -----------------
1.0 समय 37ms 73ms 68ms 184ms 73ms 21ms
if-तत्काल 1.0 1.0 1.0 2.6 1.0 1.0
if-indirect 1.2 1.8 3.3 3.8 2.6 1.0
स्विच-तत्काल 2.0 1.1 2.0 1.0 2.8 1.3
स्विच-रेंज 38.1 10.6 2.6 7.3 20.9 10.4
स्विच-रेंज 2 31.9 8.3 2.0 4.5 9.5 6.9
स्विच-अप्रत्यक्ष-सरणी 35.2 9.6 4.2 5.5 10.7 8.6
सरणी-रैखिक-स्विच 3.6 4.1 4.5 10.0 4.7 2.7
सरणी-बाइनरी-स्विच 7.8 6.7 9.5 16.0 15.0 4.9

फ़ॉउलिंग संस्करणों के साथ विंडोज 7 32 बिट पर प्रदर्शन किया गया टेस्ट: क्रोम 21.0.1180.89m , फ़ायरफ़ॉक्स 15.0 , ओपेरा 12.02 , MSIE 9.0.8112 , सफारी 5.1.7 । लिनक्स 64 बिट बॉक्स पर नोड चलाया गया था क्योंकि विंडोज के लिए Node.js पर टाइमर रिज़ॉल्यूशन 1ms के बजाय 10ms था।

अगर-तत्काल

यह सभी परीक्षण किए गए वातावरणों में सबसे तेज़ है, सिवाय ... ड्रमोल MSIE के! (अचंभा अचंभा)। इसे लागू करने के लिए यह अनुशंसित तरीका है।

if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else

अगर-अप्रत्यक्ष

यह एक संस्करण है, switch-indirect-arrayलेकिन ifइसके बजाय -statements के साथ और switch-indirect-arrayलगभग सभी परीक्षण किए गए वातावरण की तुलना में बहुत तेज़ प्रदर्शन करता है।

values=[
   1000,  2000, ... 30000
];
if (val < values[0]) { /* do something */ } else
if (val < values[1]) { /* do something */ } else
...
if (val < values[29]) { /* do something */ } else

स्विच तत्काल

यह सभी परीक्षण किए गए वातावरण में बहुत तेज़ है, और वास्तव में MSIE में सबसे तेज़ है। यह तब काम करता है जब आप एक सूचकांक प्राप्त करने के लिए गणना कर सकते हैं।

switch (Math.floor(val/1000)) {
  case 0: /* do something */ break;
  case 1: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

स्विच दूरी

यह ओपेरा को छोड़कर सभी परीक्षण किए गए वातावरणों में सबसे तेज़ से लगभग 6 से 40 गुना धीमा है जहां इसे लगभग डेढ़ गुना लंबा लगता है। यह धीमा है क्योंकि इंजन को प्रत्येक मामले के लिए दो बार मूल्य की तुलना करना पड़ता है। हैरानी की बात यह है कि क्रोम में सबसे तेज संचालन की तुलना में इसे पूरा करने में क्रोम को लगभग 40 गुना अधिक समय लगता है, जबकि एमएसआईई को केवल 6 गुना लंबा समय लगता है। लेकिन 1337ms (!) में MSIE के पक्ष में वास्तविक समय का अंतर केवल 74ms था।

switch (true) {
  case (0 <= val &&  val < 1000): /* do something */ break;
  case (1000 <= val &&  val < 2000): /* do something */ break;
  ...
  case (29000 <= val &&  val < 30000): /* do something */ break;
}

स्विच-सीमा 2

यह एक वेरिएंट है, switch-rangeलेकिन केवल एक ही मामले में तुलना करता है और इसलिए तेजी से, लेकिन अभी भी ओपेरा को छोड़कर बहुत धीमा है। केस स्टेटमेंट का क्रम महत्वपूर्ण है क्योंकि इंजन प्रत्येक मामले का स्रोत कोड ऑर्डर ECMAScript262: 5 12.11 में परीक्षण करेगा

switch (true) {
  case (val < 1000): /* do something */ break;
  case (val < 2000): /* do something */ break;
  ...
  case (val < 30000): /* do something */ break;
}

स्विच-अप्रत्यक्ष सरणी

इस प्रकार में श्रेणियाँ एक सरणी में संग्रहीत की जाती हैं। यह सभी परीक्षण किए गए वातावरण में धीमा है और क्रोम में बहुत धीमा है।

values=[1000,  2000 ... 29000, 30000];

switch(true) {
  case (val < values[0]): /* do something */ break;
  case (val < values[1]): /* do something */ break;
  ...
  case (val < values[29]): /* do something */ break;
}

सरणी रेखीय-खोज

यह किसी सरणी में मानों की रेखीय खोज और निश्चित मानों के साथ स्विच स्टेटमेंट का संयोजन है। जब कोई रनटाइम तक मानों को ज्ञात नहीं है, तो इसका उपयोग करना चाहता है। यह प्रत्येक परीक्षण किए गए वातावरण में धीमा है, और MSIE में लगभग 10 गुना लंबा है।

values=[1000,  2000 ... 29000, 30000];

for (sidx=0, slen=values.length; sidx < slen; ++sidx) {
  if (val < values[sidx]) break;
}

switch (sidx) {
  case 0: /* do something */ break;
  case 1: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

सरणी-द्विआधारी स्विच

यह एक प्रकार है, array-linear-switchलेकिन एक द्विआधारी खोज के साथ। दुर्भाग्य से यह रैखिक खोज की तुलना में धीमी है। मुझे नहीं पता कि यह मेरा कार्यान्वयन है या यदि रैखिक खोज अधिक अनुकूलित है। यह भी हो सकता है कि कीस्पेस छोटा है।

values=[0, 1000,  2000 ... 29000, 30000];

while(range) {
  range = Math.floor( (smax - smin) / 2 );
  sidx = smin + range;
  if ( val < values[sidx] ) { smax = sidx; } else { smin = sidx; }
}

switch (sidx) {
  case 0: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

निष्कर्ष

यदि प्रदर्शन महत्वपूर्ण है, उपयोग if-statements या switchतत्काल मूल्यों के साथ।


128
इसकी बहुत विस्तार और सुव्यवस्थित संरचना के साथ इसका उत्तर देखना दुर्लभ है। बिग +1
रिक डोनोहे

10
इस समस्या के प्रदर्शन पक्ष की व्याख्या के लिए बिग +1!
ज़ोल्टन श्मिट

16
यही कारण है कि स्टैकओवरफ्लो उत्तर के लिए सबसे अच्छे स्थानों में से एक है। यह एक "कालातीत" उत्तर है, शानदार नौकरी और jsfiddle के लिए धन्यवाद!
जेसी

1
grt की जानकारी और स्पष्टीकरण
JayKandari

3
मैं वास्तव में चाहता हूं कि मैं +2 कर सकता हूं, ऐसा विस्तृत जवाब!
कास्पर ली

96

एक विकल्प:

var scrollleft = 1000;
switch (true)
{
    case (scrollleft > 1000):
      alert('gt');
      break;
    case (scrollleft <= 1000):
      alert('lt');
      break; 
}

डेमो: http://jsfiddle.net/UWYzr/


4
यह अधिक मूल्यवान समाधान है। +1
IcanDivideBy0

1
क्या यह वैसा ही नहीं है if(...) else if(...)? यह बचता है, ifलेकिन मेरे लिए एक सुंदर प्रतिस्थापन की तरह काफी आवाज नहीं करता है।
pimvdb

7
कोड के लिए सुरुचिपूर्ण, यह प्रदर्शन को नुकसान पहुंचाता है। यह क्रोम का उपयोग करने की तुलना में क्रोम में लगभग 30 गुना धीमा है if। मेरा जवाब यहाँ
कुछ

1
हालाँकि ऐसा प्रदर्शन दंड नगण्य है, जब डेटा को संभाला नहीं जा रहा है, यह बड़ा नहीं है और हो सकता है कि इसका फ़ंक्शन केवल एक उपयोगकर्ता इनपुट को मान्य करने की तरह लागू हो, तो ऐसे मामले में प्रदर्शन के बजाय पठनीयता को चुना जाता है।
जेसुको फ्रेंको

1
यही वह है जिसकी तलाश में मैं हूं। धन्यवाद!
अमी श्राइबर

23
switch (Math.floor(scrollLeft/1000)) {
  case 0: // (<1000)
   //do stuff
   break;
  case 1: // (>=1000 && <2000)
   //do stuff;
   break;
}

केवल तभी काम करता है जब आपके पास नियमित कदम हों ...

EDIT: चूंकि यह घोल ऊपर उठता रहता है, इसलिए मुझे सलाह देनी चाहिए कि मोफोलो का घोल एक बेहतर तरीका है


1
मैंने Math.round(scrollLeft/1000)वैसे ही इस्तेमाल किया।
स्विट्ज

@Switz - बस ध्यान रखें कि 999 <1000 मामले में 0 पर गिरता है। लेकिन Math.round (999/1000) 1 मामले में आता है। इसके अलावा, ऊपर एक टाइपो है, उस मामले में 1 है = = 1000, न कि केवल 1000। ।
इगोर

मोफोलो के समाधान के साथ केवल समस्या यह है कि यह IcanDivideBy0 द्वारा क्रोम की तुलना में लगभग 30 गुना धीमा है। नीचे मेरा जवाब देखें।
कुछ

6

आप मापदंड के अनुरूप मापदंड और फ़ंक्शन के साथ एक कस्टम ऑब्जेक्ट बना सकते हैं

var rules = [{ lowerLimit: 0,    upperLimit: 1000, action: function1 }, 
             { lowerLimit: 1000, upperLimit: 2000, action: function2 }, 
             { lowerLimit: 2000, upperLimit: 3000, action: function3 }];

इन मामलों में आप क्या करना चाहते हैं, इसके लिए कार्यों को परिभाषित करें (function1, function2 आदि को परिभाषित करें)

और नियमों का "मूल्यांकन" करें

function applyRules(scrollLeft)
{
   for(var i=0; i>rules.length; i++)
   {
       var oneRule = rules[i];
       if(scrollLeft > oneRule.lowerLimit && scrollLeft < oneRule.upperLimit)
       {
          oneRule.action();
       }
   }
}

ध्यान दें

मैं बयान का उपयोग करते हुए 30 से नफरत है

कई बार अगर बयानों को पढ़ना और बनाए रखना आसान होता है। जब आप बहुत सारी शर्तें रखते हैं तो मैं केवल उपरोक्त की सिफारिश करूंगा और भविष्य में बहुत अधिक वृद्धि की संभावना होगी।

अपडेट करें
As @Brad ने टिप्पणियों में बताया, यदि परिस्थितियाँ पारस्परिक रूप से अनन्य हैं (केवल एक समय में उनमें से कोई एक सत्य हो सकता है), ऊपरी सीमा की जाँच करना पर्याप्त होना चाहिए:

if(scrollLeft < oneRule.upperLimit)

बशर्ते कि शर्तों को आरोही क्रम में परिभाषित किया जाए (पहले सबसे कम 0 to 1000, और फिर 1000 to 2000उदाहरण के लिए)


action=function1- ये कॉलन नहीं होना चाहिए? ;-) - आप इसे केवल एक ऊपरी सीमा के लिए भी रिफ्लेक्टर कर सकते हैं, क्योंकि उन्मूलन की प्रक्रिया के कारण, आप दो समूहों में नहीं गिर सकते हैं - जब तक कि आपका इरादा नहीं था (कई कार्यों को संभव करना)।
ब्रैड क्रिस्टी

@ ब्रैड क्रिस्टी ऑफ़ कोर्स
निवास

@ ब्रैड, नहीं, यह मेरा उद्देश्य नहीं था, और आप सही हैं, ऊपरी सीमा पर्याप्त होनी चाहिए। एक अद्यतन के रूप में जोड़ देगा ...
निवाज़

मुझे यह एक संक्षिप्त और साफ +1
pvvdb

3

वास्तव में आप क्या कर रहे हैं //do stuff?

आप कुछ ऐसा करने में सक्षम हो सकते हैं:

(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc. 

3

यदि यह काम करेगा, तो अप्रयुक्त और अनिश्चित, लेकिन कुछ if statementsपहले क्यों नहीं , के लिए चर सेट करने के लिए switch statement

var small, big;

if(scrollLeft < 1000){
    //add some token to the page
    //call it small
}


switch (//reference token/) {
  case (small):
   //do stuff
   break;
  case (big):
   //do stuff;
   break;
}


1

स्वीकृत उत्तर को अपडेट करना (अभी तक टिप्पणी नहीं कर सकता)। क्रोम में डेमो jsfiddle का उपयोग करके 1/12/16 के रूप में, स्विच-तत्काल सबसे तेज़ समाधान है।

परिणाम: समय संकल्प: 1.33

   25ms "if-immediate" 150878146 
   29ms "if-indirect" 150878146
   24ms "switch-immediate" 150878146
   128ms "switch-range" 150878146
   45ms "switch-range2" 150878146
   47ms "switch-indirect-array" 150878146
   43ms "array-linear-switch" 150878146
   72ms "array-binary-switch" 150878146

ख़त्म होना

 1.04 (   25ms) if-immediate
 1.21 (   29ms) if-indirect
 1.00 (   24ms) switch-immediate
 5.33 (  128ms) switch-range
 1.88 (   45ms) switch-range2
 1.96 (   47ms) switch-indirect-array
 1.79 (   43ms) array-linear-switch
 3.00 (   72ms) array-binary-switch

यह वास्तव में निर्भर करता है - 15ms "if-तत्काल" 15ms "यदि परोक्ष" 15ms "स्विच-तत्काल" 37ms "स्विच-रेंज" 28ms "स्विच-रेंज 2" 35ms "स्विच-इनडायरेक्ट-सरणी" 29ms "सरणी-रैखिक-स्विच" 62ms "सरणी-बाइनरी-स्विच" समाप्त 1.00 (15ms) यदि-तत्काल 1.00 (15ms) यदि-अप्रत्यक्ष 1.00 (15ms) स्विच-तत्काल 2.47 (37ms) स्विच-रेंज 1.87 (28ms) स्विच-रेंज 2 2.33 (35ms) स्विच- अप्रत्यक्ष सरणी 1.93 (29ms) सरणी रेखीय स्विच 4.13 (62ms) सरणी-द्विआधारी स्विच क्रोम संस्करण 48.0.2564.109 (64-बिट) मैक ओएस एक्स 10.11.3
RenaissanceProgrammer

मैक ओएस एक्स और सफारी आईओएस 9.3 पर एटीएम सफारी 9.X, "अगर-तत्काल" स्पष्ट विजेता है
RenaissanceProgrammer

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

1

मेरे मामले में (रंग-कोडिंग एक प्रतिशत, प्रदर्शन-महत्वपूर्ण कुछ भी नहीं), मैंने जल्दी से यह लिखा:

function findColor(progress) {
    const thresholds = [30, 60];
    const colors = ["#90B451", "#F9A92F", "#90B451"];

    return colors.find((col, index) => {
        return index >= thresholds.length || progress < thresholds[index];
    });
}

1

मैं बयान का उपयोग करते हुए 30 से नफरत है

हाल ही में मेरी भी यही स्थिति थी, कि मैंने इसे कैसे हल किया:

इससे पहले:

if(wind_speed >= 18) {
    scale = 5;
} else if(wind_speed >= 12) {
    scale = 4;
} else if(wind_speed >= 9) {
    scale = 3;
} else if(wind_speed >= 6) {
    scale = 2;
} else if(wind_speed >= 4) {
    scale = 1;
}

उपरांत:

var scales = [[4, 1], [6, 2], [9, 3], [12, 4], [18, 5]];
scales.forEach(function(el){if(wind_speed > el[0]) scale = el[1]});

और यदि आप "1, 2, 3, 4, 5" सेट करते हैं तो यह और भी सरल हो सकता है:

var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.