संख्या को गिनने के लिए शेल फ़ंक्शन में गलती


12

असाइनमेंट के लिए मुझे एक फ़ंक्शन लिखना होगा जो संख्याओं के अनुक्रम के साथ प्रदान किए जाने पर सम संख्याओं को प्रिंट करता है।

मैंने पिछले असाइनमेंट के लिए उपयोग किए गए कोड के टुकड़े का इस्तेमाल किया था (यह जानने के लिए कि संख्या कितनी थी 1और 0जब संख्या विषम थी)

मेरी समस्या अब यह है कि मेरा कार्य प्रिंट करता रहता है 0। मैं क्या गलत कर रहा हूं?

यहाँ मेरी स्क्रिप्ट है:

#!/usr/bin/bash
# File: nevens.sh

# Write a function called nevens which prints the number of even numbers when provided with a sequence of numbers.
# Check: input nevens 42 6 7 9 33 = output 2

function nevens {

        local sum=0

        for element in $@
        do
                let evencheck=$(( $# % 2 ))
                if [[ $evencheck -eq 0 ]]
                then
                        let sum=$sum+1
                fi
        done

        echo $sum
}

2
अपने शबंग '#! / usr / bin / bash -x' में लिखें फिर आप देखेंगे कि वास्तव में क्या होता है।
ज़ियाज़िस

+1 यह बताने के लिए कि यह होमवर्क है - और मदद के लायक इस पर काफी मेहनत की गई है।
जो

जवाबों:


20

आप बस $#( $) elementको forलूप में बदलना भूल गए :

function nevens {
  local sum=0
  for element in $@; do
    let evencheck=$(( element % 2 ))
    if [[ $evencheck -eq 0 ]]; then
      let sum=sum+1
    fi
  done
  echo $sum
}

अब फ़ंक्शन का परीक्षण करने के लिए:

$ nevens 42 6 7 9 33
2
$ nevens 42 6 7 9 33 22
3
$ nevens {1..10..2} # 1 to 10 step 2 → odd numbers only
0
$ nevens {2..10..2} # 2 to 10 step 2 → five even numbers
5

17

@ डार्टर्ट को मुख्य समस्या मिली है, मैं कुछ कोड समीक्षा दूंगा:

  1. शेबंग: /usr/bin/bashउबंटू में नहीं है। यह है /bin/bash
  2. यह अच्छा है कि आपने घोषित किया है sum local, और फ़ंक्शन के बाहर चर नाम स्थान को प्रदूषित करने से बचा है। इसके अतिरिक्त, आप -iविकल्प का उपयोग करके इसे पूर्णांक चर घोषित कर सकते हैं :

    local -i sum=0
  3. हमेशा अपने चर (और मापदंडों) को उद्धृत करें! यह इस लिपि में आवश्यक नहीं है, लेकिन इसमें एक बहुत अच्छी आदत है:

    for element in "$@"
    do
    

    उस ने कहा, आप in "$@"यहाँ छोड़ सकते हैं :

    for element
    do
    

    जब in <something>नहीं दिया जाता है, तो forलूप निहित रूप से तर्कों पर केंद्रित होता है। यह उद्धरणों को भूलने जैसी गलतियों से बच सकता है।

  4. गणना करने और फिर परिणाम की जांच करने की कोई आवश्यकता नहीं है। आप सीधे गणना कर सकते हैं if:

    if (( (element % 2) == 0 ))
    then
        ((sum = sum + 1))
    fi
    

    (( ... ))है गणित संदर्भ । यह [[ ... ]]अंकगणित की जाँच करने के लिए अधिक उपयोगी है , और इसके अलावा आप $पहले चर (जो इसे पढ़ना आसान बनाता है, IMHO) को छोड़ सकते हैं ।

  5. यदि आप सम-चेकिंग भाग को एक अलग फ़ंक्शन में स्थानांतरित करते हैं, तो यह पठनीयता और पुन: प्रयोज्यता में सुधार कर सकता है:

    function evencheck
    {
        return $(( $1 % 2 ))
    }
    function nevens
    {
        local -i sum=0
        for element
        do
            # `if` implicitly checks that the returned value/exit status is 0
            if evencheck "$element"
            then
                (( sum++ ))
            fi
        done
        echo "$sum"
    }
    

1
यदि आप एक टर्स लूप बॉडी उपयोग के लिए देख रहे हैं sum=$((sum + 1 - element % 2))
डेविड फ़ॉस्टर

1
@DavidFoerster Terser और कम पठनीय। ;-)
कोनराड रुडोल्फ

@DavidFoerster: मेरा एक ही विचार था कि आपको सीधे mod-2 परिणाम का उपयोग करना चाहिए। (या बेहतर है, &1कम बिट की जांच करने के लिए यदि वह आपके लिए अधिक पठनीय है)। लेकिन हम इसे और अधिक पठनीय बना सकते हैं: के sum=$((sum + !(element&1) ))बजाय बूलियन व्युत्क्रम का उपयोग करने के लिए +1 - condition। या बस के साथ विषम तत्वों की गिनती करें ((odd += element&1)), और अंत में प्रिंट करें echo $(($# - element)), क्योंकि even = total - odd
पीटर कॉर्ड्स

अच्छा काम, और शुरुआती चीजों को इंगित करने के लिए अच्छा है जो शुरुआती को याद करते हैं, जैसे local -iऔर sum++
धान लैंडौ

4

मुझे यकीन नहीं है कि आप अन्य समाधानों के लिए खुले हैं। इसके अलावा मुझे नहीं पता कि क्या आप बाहरी उपयोगिताओं का उपयोग कर सकते हैं, या यदि आप विशुद्ध रूप से बैश बिल्डिंग्स तक सीमित हैं। यदि आप उपयोग कर सकते हैं grep, उदाहरण के लिए, आपका कार्य पूरी तरह से सरल हो सकता है:

function nevens {
    printf "%s\n" "$@" | grep -c '[02468]$'
}

यह प्रत्येक इनपुट पूर्णांक को अपनी लाइन पर रखता है, और फिर grepएक समान अंक में समाप्त होने वाली रेखाओं को गिनने के लिए उपयोग करता है।


अपडेट - @PeterCordes ने बताया कि हम बिना grep के भी ऐसा कर सकते हैं - बस शुद्ध बैश, इसलिए जब तक इनपुट सूची में सिर्फ अच्छी तरह से बने पूर्णांक (बिना दशमलव बिंदुओं के) शामिल हैं:

function nevens{
    evens=( ${@/%*[13579]/} )
    echo "${#evens[@]}"
}

यह evensसभी बाधाओं को छानकर, फिर उस सूची की लंबाई को वापस बुलाकर एक सूची बनाकर काम करता है ।


दिलचस्प दृष्टिकोण। बेशक यह 3.0एक समान संख्या के रूप में गिना जाएगा ; सवाल सटीक नहीं था कि नंबर किस रूप में होंगे।
जी-मैन का कहना है कि 'मोनिका'

@ जी-मैन चूंकि बैश फ्लोटिंग पॉइंट अंकगणित का समर्थन नहीं करता है, यह पूर्णांक मानने के लिए सुरक्षित है
muru

चूँकि प्रश्न "सम" (और, संक्षेप में, "विषम") संख्याओं का उल्लेख करता है, इसलिए यह मान लेना सुरक्षित है कि यह पूर्णांक के साथ बात कर रहा है। मैं यह नहीं देखता कि उपयोगकर्ता द्वारा उपयोग किए जाने वाले टूल की क्षमताओं और सीमाओं से प्रश्न के बारे में निष्कर्ष निकालना कैसे मान्य है। याद रखें: प्रश्न कहता है कि यह एक असाइनमेंट है - मैं स्कूल के लिए अनुमान लगाता हूं, क्योंकि यह नौकरी से बहुत तुच्छ है। स्कूल के शिक्षक कुछ पागल चीजों के साथ आते हैं।
जी-मैन का कहना है कि 'मोनिका'

2
बैश अगर हम कोई तत्व ग्रहण कर सकते हैं खाली स्थान के होते हैं अपने आप ही एक सूची को फ़िल्टर कर सकते हैं: का उपयोग कर रिक्त स्ट्रिंग के साथ बदल दिया विषम संख्या के साथ आर्ग सूची का विस्तार ${/%/}पर @सरणी स्ट्रिंग के अंत में एक मैच, एक सरणी प्रारंभकर्ता अंदर की आवश्यकता होती है। गिनती प्रिंट करें। इसे परिभाषित करने और चलाने के लिए वन-लाइनर के रूप में foo(){ evens=( ${@/%*[13579]/} ); echo "${#evens[@]} even numbers"; printf "%s\n" "${evens[@]}"; }; foo 135 212 325 3 6 3 4 5 9 7 2 12310:। वास्तव में डीबगिंग के लिए सूची मुद्रण शामिल है। प्रिंट्स 5 even numbers 212 6 4 2 12310(सेप लाइनों पर)
पीटर कॉर्ड्स

1
संभवतः ZSH के पास एक सूची को ठीक से फ़िल्टर करने के लिए कुछ है, बजाय एक नए सरणी के पुनर्निर्माण के लिए शब्द विभाजन पर निर्भर करता है (मैं थोड़ा हैरान था, केवल हर तत्व के लिए स्केलर स्ट्रिंग विस्तार सामान लागू नहीं किया गया था)। बड़ी सूचियों के लिए, मुझे आश्चर्य नहीं होगा यदि grepवास्तव में इससे अधिक तेज था bash। हम्म, मुझे आश्चर्य है कि अगर कोई कोडगॉल्फ सवाल है जहां मैं उस बैश फ़ंक्शन को पोस्ट कर सकता हूं: P
पीटर कॉर्डेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.