在循环内将负整数变为正整数

在循环内将负整数变为正整数

我正在尝试添加由空格分隔的单行整数并找到它们的绝对值。共有 5 个整数,其中一个为负数,其他为正数。我正在尝试找到一种方法使当前的负值变为正值,以便找到所有数字的绝对值。这是我到目前为止所拥有的。

read input
# 1, 5, -17, 32, 12
# expected absolute value: 67
absolute_value()
{
    local absolute_value=0

    for nums in $input;
    do
    ((absolute_value += nums))

    done
    echo $absolute_value
}
absolute_value

我的答案是 33,预期答案是 67。它们当然是相加的,但由于其中一个输入数字可能是负数,所以它给我的是总和而不是绝对值。我很困惑,一直在四处寻找答案,但我就是想不出答案。 Bash 不是我最擅长的语言,所以我可能会忽略它。

答案1

嗯,怎么样绝对值定义?

if [ "$num" -lt 0 ]; then
    num=$((-num))
fi

无论如何,这:

for nums in $input

依赖于分词并且有点丑陋。如果有人输入非数字或全局字符,您也会得到有趣的效果。由于您使用的是 Bash,因此您可以通过将值读取到带有read -a.另外,我们还可以使用[[ var -lt 0 ]].

然而,仅仅这样做并不好,因为 Bash 中的算术扩展是危险的。通过数组索引和命令替换可以很容易地注入命令,shell 将执行它们。因此,我们确实需要首先检查接收到的值是否是数字。

#!/bin/bash
read -a nums
sum=0
for a in "${nums[@]}"; do
    if [[ $a = *[^-0-9]* ]]; then
        echo "invalid number: $a"
        exit 1
    fi 
    if [[ a -lt 0 ]]; then
        sum=$((sum + -a))
    else
        sum=$((sum +  a))
    fi
done
echo "$sum"

请注意,Bash 会将以 和 开头的数字分别解释00x八进制和十六进制。


或者,您知道,只需使用真正的编程语言即可,这样您就不需要手动完成所有操作:

$ python3 -c 'print(sum(map(lambda x: abs(int(x)), str.split(input()))))'
1 5 -17 32 12
67

答案2

您可以使用参数替换来删除减号:

读取输入
# 1, 5, -17, 32, 12
# 期望绝对值:67
绝对值() {
    局部绝对值=0

    对于 $input 中的数字;做
      ((绝对值 +=${nums#-}))
    完毕
    回显$绝对值
}

绝对值

为了避免使用 for 循环,您可以尝试这样做:

printf "%s\n" ${input/-/} | awk '{ sum += $1 } END { print sum }'

我会使用 while 循环和数组来控制用户可以执行多少输入,并不断询问输入是否错误:

declare -a arr
declare -a arr_abs
echo "Enter four numbers:"

while true; do
  read num
  [[ $num =~  ^[^-0-9]$ ]] && echo "Not a number..." && continue
  # keep the original values for any other use
  arr+=($num)
  # create an array with absolute values
  arr_abs+=(${num#-})
  [[ ${#arr[@]} -eq 4 ]] && break
done

absolute_value() {
   sum=$(printf "%s\n" ${arr_abs[@]} | awk '{ sum += $1 } END { print sum }')
   echo "The absolute sum is $sum"
}

absolute_value

相关内容