优化循环,从外部文件传递参数,在awk中命名数组参数

时间:2014-01-19 00:46:53

标签: arrays shell loops awk

是一个awk新手。在UNXUTILS中使用Windows-GNU gawk。

在我的文件中有2种顺序排列日期和时间顺序的记录,30字段订单记录(以“O”开头),其中数量是第15个字段,18 -field贸易记录(以“T”开头),其中数量是第8个字段。基础研究数据是2006年4月15天的历史档案印度股票市场数据,约1000家公司,包括所有约1亿个单独的订单或交易记录。我的测试数据是2个日期的500条记录,以及大约200家公司。

此时我的目标只是计算每家公司和每个日期,即公司日期的累计订单数量和交易数量。

原始数据按日期和时间排序(公司明显混乱,就像通常不按字母顺序投票的选民!)。我现在有两个单独的文本文件,一个包含只有不同公司符号的列表;另一个是不同的日期,每行一个。

我想尝试以一种不需要让我通过所有记录一遍又一遍地为每个公司和日期完成计算的方式来完成计算。给定公司= FIRM_1和日期= DATE_1的基本计算很容易,例如我有什么相似

# For each order record with firm_symbol = FIRM_1, date = DATE_1, 
# cumulate its Order quantity ($15).

( /^O/ && $4~/FIRM_1/ ) && $2~/DATE_1/ 
            { Order_Q[FIRM_1_DATE_1]=Order_Q[FIRM_1_DATE_1]+$15] }

# For each trade record with firm_symbol = FIRM_1, date = DATE_1, 
#cumulate its Trade quantity ($8).

( /^T/ && $4~/FIRM_1/ ) && $2~/DATE_1/ 
            { Trade_Q[FIRM_1_DATE_1]=Trade_Q[FIRM_1_DATE_1]+$8] }

END { print "FIRM_1 ", "DATE_1 ", Order_Q[FIRM_1_DATE_1], Trade_Q[FIRM_1_DATE_1] }

问题是如何根据基础数据的大小在所有公司和日期上构建智能循环。有几个相关的问题。

  1. 我知道FIRM_1这个名称不需要在这个awk脚本中进行硬编码,但可以作为命令行参数给出。 但是,可以更进一步,并获取awk从一个单独的文件中的名称列表顺序取名,每行一个?(如果这是可行的,那么从日期列表中取日期将也是可能的。)

  2. 我构建了数组参数名称,以保存订单数量和交易数量,知道FIRM_1和DATE_1。如果我们成功解决了上面的1,可以在运行时在awk内部实时构建数组参数名称,例如FIRM_1_DATE_1和FIRM_1_DATE_1吗?是否允许字符串连接以帮助形成名称?

  3. 我意识到我可以使用编辑器宏或某种方法,将我的2个键,FIRM(1000个值)和DATE(15个值)组合成一个FIRM_DATE键(15000个值),然后再执行任何操作,在单独的步骤中。如果上述2是可行的,我认为这样做是没有价值的。无论如何它会有帮助吗?

  4. 原则上我们希望在内存中保留1000个公司时间15天,2个变量= 2个数组中的30,000个单元格条目,ORDER_Q和TRADE_Q。这很多吗?我使用适度的Windows桌面,我认为8GB RAM。

  5. 任何有助于减少必须多次查看原始大输入数据的建议或参考或示例将非常受欢迎。如果某些事情涉及到的不仅仅是关于awk而是关于shell脚本,那也非常受欢迎。

1 个答案:

答案 0 :(得分:2)

使用关联数组。假设$2包含公司名称和$4日期,则:

awk '/^O/ { order_qty[$2,$4] += $15 }
     /^T/ { trade_qty[$2,$4] += $8  }
     END  { for (key in order_qty) { print key, "O", order_qty[key]; }
            for (key in trade_qty) { print key, "T", trade_qty[key]; }
          }'

这不会为您提供输出中公司或日期的已定义订单。有技术可以做到这一点。这样就可以对数据进行单次传递,从而累计所有公司的结果以及所有日期的所有日期。

awk '     { if (date[$4]++ == 0) date_list[d++] = $4; # Dates appear in order
            if (firm[$2]++ == 0) firm_list[f++] = $2; # Firms appear out of order
          }
     /^O/ { order_qty[$2,$4] += $15 }
     /^T/ { trade_qty[$2,$4] += $8  }
     END  { for (i = 0; i < f; i++)
            {
                for (j = 0; j < d; j++)
                {
                    if ((qty = order_qty[firm_list[i],date_list[j]]) > 0)
                        print firm_list[i], date_list[j], "O", qty
                    if ((qty = trade_qty[firm_list[i],date_list[j]]) > 0)
                        print firm_list[i], date_list[j], "T", qty
                }
            }
          }'

如果您希望公司处于特定(例如已排序)的订单,请在打印前对公司列表进行排序。 GNU awk提供内置的排序功能。否则,您将必须编写awk函数来执行此操作。 (有关在awk中编写排序函数的详细信息,请参阅Programming PearlsMore Programming Pearls(或两者)。

警告:未经测试的代码。