前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一道shell脚本的统计题

一道shell脚本的统计题

作者头像
用户3147702
发布2022-06-27 12:31:38
1520
发布2022-06-27 12:31:38
举报
文章被收录于专栏:小脑斧科技博客

1. 问题描述

1.1. 输入格式:

a. 若干行数据,每行数据有3列内容,列之间\t分割。 b. 第一列表示属性1,第二列表示属性2,第三列表示属性3。 c. 每一个属性的可能取值在一次计算过程中是固定的,比如属性1只可是0,1,2,4,属性2只可能是29,35,55,70。 d. 每一个属性的可能取值在不同的计算过程中可能是变化的,比如第一次计算时属性1只可能是0,1,2,4,第二次计算时,属性1的可能取值多了一个5,即第二次计算时,属性1只可能取0,1,2,4,5。

1.2. 输入的例子:

0 29 50。 1 35 60。 0 29 60。

1.3. 输出的结果:

Flag 29 35。 0 2 0。 1 0 1。

1.4. 输出结果的解释:

a. Flag是固定的,就输出成这个。 b. 第一行除flag之外,是属性2的所有可能取值。 c. 第一列除flag之外,是属性1的所有可能取值。 d. 其余位置数字的含义:例如:第二行第二列的2,表示输入数据中,属性1的值是0并且属性2的值是29,这样的数据有2行。

2. 解答代码

2.1. main.sh

代码语言:javascript
复制
#!/bin/bash

bash count.sh > output.txt &&
bash count_result.sh > result.txt &&
cat result.txt
echo

2.2. cout.sh

代码语言:javascript
复制
#!/bin/bash

sort -k 1,2 input.txt > output_a.txt &&
    b="<![INITED]>";
i=1;

while read line; do
    y=`echo $line | awk '{ print $1"\t"$2 }'`;
    if [ "$b" != "<![INITED]>" ]; then
        if [ "$y" != "$b" ]
        then
            echo -e ${b}"\t"${i};
            i=1;
        else
            i=$((i+1))
        fi
    fi
    b=$y;
done < output_a.txt

echo -e ${b}"\t"${i};

2.3. count_result.sh

代码语言:javascript
复制
#!/bin/bash

echo -e "Flag\t\c"

i=0
x="<![INITED]>"
while read line; do
    b=`echo -e $line | awk '{print $1}'`
    if [ "$b" != "$x" ]; then
        array_1[$((i))]=$b
        x=${array_1[$((i))]}
        i=$((i+1))
    fi
done < output.txt

sort -k 2 output.txt > out2.txt

i=0
x="<![INITED]>"
while read line; do
    b=`echo -e $line | awk '{print $2}'`
    if [ "$b" != "$x" ]; then
        array_2[$((i))]=$b
        x=${array_2[$((i))]}
        i=$((i+1))
    fi
done < out2.txt

for var in ${array_2[@]}; do
    echo -e $var"\t\c"
done

echo
echo -e ${array_1[0]}"\t\c"
i=0
j=0
while read line; do
    e1=`echo -e $line | awk '{ print $1 }'`
    e2=`echo -e $line | awk '{ print $2 }'`
    e3=`echo -e $line | awk '{ print $3 }'`

    if [ $e1 != ${array_1[$((j))]} ]; then
        while [ $((i)) -lt ${#array_2[@]} ]; do
            echo -e 0"\t\c"
            i=$((i+1))
        done
        i=0
        j=$((j+1))
        echo
        echo -e ${array_1[$((j))]}"\t\c"
    fi

    while [ 1 ]; do
        if [ $e2 == ${array_2[$((i))]} ]; then
            echo -e $e3"\t\c"
            break;
        elif [ $e2 -gt ${array_2[$((i))]} ]; then
            echo -e 0"\t\c"
            i=$((i+1))
        fi
    done
    i=$((i+1))
done < output.txt

while [ $((i)) -lt ${#array_2[@]} ]; do
    echo -e 0"\t\c"
    i=$((i+1))
done

rm -rf out*.txt

3. 缺陷

代码语言:javascript
复制
while read line; do ... done

这个方式读取文件效率过低,如果输入为十万行级别或更高,运行时间是不可接受的。 因此,这个方案无奈被弃置。

4. awk 改进

4.1. awk_main.sh

代码语言:javascript
复制
cat zeyu_test_input | awk -F"\t" -f count.awk -v a=2 b=4 > out.txt &&
sort -k 1,2 out.txt > output.txt &&
sh count_result.sh > result.txt &&

echo >> result.txt
echo >> result.txt

cat zeyu_test_input | awk -F"\t" -f count.awk -v a=2 b=5 > out.txt &&
sort -k 1,2 out.txt > output.txt &&
sh count_result.sh >> result.txt &&

cat result.txt &&
echo

4.2. count.awk

代码语言:javascript
复制
{
    y=$a"\t"$b;
    if (y in A)
        A[y]++;
    else
        A[y] = 1;
};
END \
{
    for (k in A)
    {
        print k"\t"A[k];
    }
}

4.3. count_result.sh

代码语言:javascript
复制
#!/bin/bash

echo -e "Flag\t\c"

i=0
x="<![INITED]>"
while read line; do
    b=`echo $line | awk '{print $1}'`
    if [ "$b" != "$x" ]; then
        array_1[$((i))]=$b
        x=${array_1[$((i))]}
        i=$((i+1))
    fi
done < output.txt

sort -k 2 output.txt > out2.txt

i=0
x="<![INITED]>"
while read line; do
    b=`echo $line | awk '{print $2}'`
    if [ "$b" != "$x" ]; then
        array_2[$((i))]=$b
        x=${array_2[$((i))]}
        i=$((i+1))
    fi
done < out2.txt

for var in ${array_2[@]}; do
    echo -e $var"\t\c"
done

echo -e "total\t"
echo -e ${array_1[0]}"\t\c"
i=0
j=0
x_t=0
while read line; do
    e1=`echo $line | awk '{ print $1 }'`
    e2=`echo $line | awk '{ print $2 }'`
    e3=`echo $line | awk '{ print $3 }'`

    if [ $e1 != ${array_1[$((j))]} ]; then
        while [ $((i)) -lt ${#array_2[@]} ]; do
            echo -e 0"\t\c"
            i=$((i+1))
        done
        i=0
        j=$((j+1))
        echo $x_t
        x_t=0
        echo -e ${array_1[$((j))]}"\t\c"
    fi

    while [ 1 ]; do
        if [ $e2 == ${array_2[$((i))]} ]; then
            echo -e $e3"\t\c"
            y_t[$((i))]=$(($((${y_t[$((i))]}))+$e3));
            x_t=$((x_t+e3))
            break;
        elif [ $e2 -gt ${array_2[$((i))]} ]; then
            echo -e 0"\t\c"
            i=$((i+1))
        fi
    done
    i=$((i+1))
done < output.txt

while [ $((i)) -lt ${#array_2[@]} ]; do
    echo -e 0"\t\c"
    i=$((i+1))
done
echo $x_t

i=0
echo -e "total\t\c"
for var in ${y_t[@]}; do
    echo -e $var"\t\c"
    i=$((i+var))
done
echo $i

rm -rf out*.txt

5. 执行结果

运行一个 1620590 行的数据用时 16 秒。 执行结果如图所示:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-06-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 问题描述
    • 1.1. 输入格式:
      • 1.2. 输入的例子:
        • 1.3. 输出的结果:
          • 1.4. 输出结果的解释:
          • 2. 解答代码
            • 2.1. main.sh
              • 2.2. cout.sh
                • 2.3. count_result.sh
                • 3. 缺陷
                • 4. awk 改进
                  • 4.1. awk_main.sh
                    • 4.2. count.awk
                      • 4.3. count_result.sh
                      • 5. 执行结果
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档