分享

Linux读取键值对类型文件,分组求每个key的sum(value)

BB_BDATA 2018-7-9 10:48:16 发表于 其它 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 5 9880
有一个问题,需求如下:
有一个文件,格式如下
a 10
b 11
a 11
a 15
b 24
b 10
基本类似于键值对的格式,分隔符是空格,先要对第一列进行分组,并得到对应第二列的value合计
例如:a的value合计为:10+11+15=36;b的value合计为:11+24+10=45,输出:
a 36
b 45
请用linux命令,或者shell实现,谢谢

已有(4)人评论

跳转到指定楼层
yaojiank 发表于 2018-7-9 20:59:39
下面\t换为空格。有问题欢迎交流
mapper.sh 程序:



awk -F"\3|\t" '{
                 for(i=0;i<NF;i++){

                       print $i "\t" 0

                }
}'

reducer.sh程序:

awk -F"\t|\3" '{
if( url[$1] == "" ){
  urlarray[$1]=1
}

else

   urlarray[$1]++
}
END{
   for url in urlarray

   do

        print url "\t" urlarray[url]

   done
}'

回复

使用道具 举报

BB_BDATA 发表于 2018-7-11 16:49:36
yaojiank 发表于 2018-7-9 20:59
下面\t换为空格。有问题欢迎交流
mapper.sh 程序:

谢谢,抽空研究学习下awk,不是很熟悉
回复

使用道具 举报

BB_BDATA 发表于 2018-7-11 16:51:15
yaojiank 发表于 2018-7-9 20:59
下面\t换为空格。有问题欢迎交流
mapper.sh 程序:

谢谢,抽空研究学习下awk,不是很熟悉
回复

使用道具 举报

BB_BDATA 发表于 2018-7-11 16:54:28
本帖最后由 BB_BDATA 于 2018-7-11 17:10 编辑

#!bin/bash

ARRAY=($(awk '{print $1}' map.txt))
#遍历数组
#echo "遍历数组:"
#for item in ${ARRAY[@]}
#do
#    echo $item
#done
#echo "----------------------------------------------"

declare -A map=()
k=0

while read line
do
   key=`echo $line|cut -d ' ' -f 1`
   value=`echo $line|cut -d ' ' -f 2`
   echo $key$value
   if [ "$k" == "0"  ]; then
      map["$key"]="$value"  
   else
     for i in ${!map[@]}
     do
       echo "遍历数组:"
       if [ "$i" == "$key"  ]; then
        echo $key${map[$key]}
        countvalue=$[map[$key]+value]
        echo $countvalue
        let map["$key"]="$[map[$key]+value]"
       else
        map["$key"]="$value"
       fi
     done         
   fi
   let k++
done < map.txt


for key in ${!map[@]}  
do  
    echo $key"|"${map[$key]}  
done  

我的实现方式如上,只是有个bug,没找到原因在哪里,现在的输出结果是:
a|15
b|20
不知道原因出在哪里了,通过打印的日志感觉let 在a那没有生效。。。

补充内容 (2018-7-12 11:04):
let map["$key"]="$[map[$key]+value]" 这句话没有生效,去掉let也没有覆盖掉原值

补充内容 (2018-7-12 11:04):
map["$key"]="$countvalue" 同样也没生效
回复

使用道具 举报

BB_BDATA 发表于 2018-7-12 15:27:16
本帖最后由 BB_BDATA 于 2018-7-12 15:32 编辑

#!bin/bash

declare -A mapcount=()
while read line
do
   key=`echo $line|cut -d ' ' -f 1`
   value=`echo $line|cut -d ' ' -f 2`
   #echo $key$value
   keys=`echo ${!mapcount[@]}`
   #echo $keys
   if [[ $keys =~ $key ]]; then
    #echo $key${mapcount[$key]}
    countvalue=0
    countvalue=$[mapcount[$key]+value]
    #echo $countvalue
    #echo "覆盖原值:"
    mapcount["$key"]="$countvalue"
   else
           #echo "新值增加:"
    mapcount["$key"]="$value"
   fi
done < map.txt


for g in ${!mapcount[@]}  
do  
    echo $g"|"${mapcount[$g]}  
done

想复杂了。。直接用map累加覆盖就行了核心思想: if [[ $keys =~ $key ]]; 判断map keys中是否包含每个key,包含:累加,不包含:新增一个key value即可
输出如下(分隔符用的|):
a|36
b|45


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条