짝수를 세는 쉘 함수의 실수


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
shebang '#! / usr / bin / bash -x'에 쓰면 정확히 무슨 일이 일어나는지 알 수 있습니다.
Ziazis

숙제라고 말하고 도움을받을만큼 열심히 노력한 것에 대해 +1.
Joe

답변:


20

루프 에서 $#( $) 로 바꾸는 것을 잊었습니다 .elementfor

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

@dessert 가 핵심 문제를 발견했습니다. 코드 검토를하겠습니다.

  1. shebang : /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
terser loop body를 찾고 있다면를 사용하십시오 sum=$((sum + 1 - element % 2)).
David Foerster

1
@DavidFoerster Terser는 읽기 쉽지 않습니다. ;-)
Konrad Rudolph 10

@DavidFoerster : mod-2 결과를 직접 사용해야한다고 생각했습니다. 또는 더 &1읽기 쉬운 하위 비트를 확인하는 것이 좋습니다 . 그러나 우리는 그것을 더 읽기 쉽게 만들 수 있습니다 : sum=$((sum + !(element&1) ))대신 부울 역을 사용하십시오 +1 - condition. 또는 단지와 홀수 요소를 계산 ((odd += element&1))하고, 마지막으로 인쇄 echo $(($# - element))하기 때문에 even = total - odd.
Peter Cordes

예를 들어 local -i, 초보자가 그리워하는 작은 일을 지적하는 것이 좋습니다 sum++.
Paddy Landau

4

다른 솔루션을 사용할 수 있는지 잘 모르겠습니다. 또한 외부 유틸리티를 사용할 수 있는지 또는 순전히 bash 내장으로 제한되는지 여부를 모르겠습니다. 당신이 사용할 수있는 경우 grep, 예를 들어, 함수는 훨씬 더 간단 할 수있다 :

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

이렇게하면 각 입력 정수가 자체 행 grep에 놓인 다음 짝수로 끝나는 행을 계산하는 데 사용 됩니다.


업데이트-@PeterCordes는 입력 목록에 잘 구성된 정수 (소수점이없는)가 포함되어 있으면 grep 없이이 작업을 수행 할 수 있다고 지적했습니다.

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

이것은 evens모든 배당률을 걸러 내고 목록의 길이를 반환하여 호출 되는 목록을 작성하여 작동 합니다.


재미있는 접근법. 물론 이것은 3.0짝수로 계산 됩니다. 숫자가 어떤 형태 일지에 대한 질문은 정확하지 않았습니다.
G-Man, 'Reinstate

bash는 부동 소수점 산술을 지원하지 않기 때문에 정수를 가정하는 것이 안전합니다.
muru

이 질문에는“짝수”(그리고 암묵적으로“홀수”) 숫자가 언급되어 있기 때문에 정수에 대해 이야기하고 있다고 가정하는 것이 다소 안전합니다. 사용자가 사용할 것으로 예상되는 도구의 기능과 한계에서 질문에 대한 결론을 도출하는 것이 얼마나 유효한지 알 수 없습니다. 기억하십시오 : 질문은 이것이 과제라고 말합니다. 이것은 학교에서 생각하기에 너무 사소한 일이기 때문에 학교에서는 추측합니다. 학교 교사들은 미친 것들을 생각해냅니다.
G-Man, 'Reinstate Monica'라고

2
Bash는 공백을 포함하는 요소가 없다고 가정 할 경우 자체적으로 목록을 필터링 할 수 있습니다 . 배열 이니셜 라이저 내부에서 문자열의 끝에 일치가 필요 ${/%/}하도록 @배열을 사용하여 홀수로 빈 문자열로 대체 된 인수 목록을 확장하십시오 . 카운트를 인쇄하십시오. 그것을 정의하고 실행하는 단일 라이너로 : 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(9
Peter Cordes

1
아마도 ZSH에는 단어 배열에 따라 새 배열을 다시 작성하는 대신 목록을 올바르게 필터링하는 것이있을 것입니다 (bash는 그렇지 않았지만 모든 요소에 스칼라 문자열 확장 항목 만 적용하는 것이 약간 놀랐습니다). 큰 목록의 경우 grep실제로보다 빠르면 놀라지 않을 것 bash입니다. 흠, 나는 그 bash 함수를 게시 할 수있는 codegolf 질문이 있는지 궁금하다. : P
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.