首页 > 解决方案 > 对文本文件中的所有字符进行操作的更快方法

问题描述

我想在一个很长的字符串上执行一个任务,我认为我需要单独对每个字符进行操作。在这样做之前,我首先尝试建立访问所有这些字符所需时间的基线

我打算使用的输入是一个文本文件,其中一行包含一个由数字组成的单词。

下面的代码是我迄今为止最好的尝试,是否有更快的方法来逐个访问字符串中的所有字符

function handle_split() {
    split=$1
    while read -N 1 char; do
        :
    done
}

while read -N 100000 split; do
    ((i=i%100)); ((i++==0)) && wait
    handle_split $split &
done < "filename.txt"

此行旨在避免同时排队超过 100 个任务

((i=i%100)); ((i++==0)) && wait

拆分的长度是根据输入的已知长度硬编码的,在这种情况下,我使用的是大约十亿个字符的字符串。


顺便说一句,我试图将我的字符串拆分转换为数组以提高性能。

function handle_split() {
    split=($@)
    for char in ${split[@]}; do
        :
    done
}

while read -N 100 split; do
   arr=($(echo $split | grep -o .))
   ((i=i%100)); ((i++==0)) && wait
   handle_split "${arr[@]}" &
done < "filename.txt"

但是这种使用数组的实现甚至比简单的 for 循环还要慢。

while read -N 1 char; do
    :
done < "filename.txt"

标签: stringbashloopstexttext-files

解决方案


GNU 或 BSDawk在这里可能是一个不错的选择:

awk 'BEGIN {FS=""}
  {for(i=1;i<=NF;i++) a[$i]++}
  END {for(i=0;i<10;i++) for(j=0;j<a[i];j++) printf "%d", i}' file

应该是关于你想要什么。解释:FS=""BEGIN块中意味着文件中的每个单个字符都是一个单独的字段。该{for(i=1;i<=NF;i++) a[$i]++}块循环遍历所有字段(1 到NF),并为每个字段递增a数组的 10 个单元之一。该END块在 END 处执行,它按数字递增的顺序打印每个数字d的次数。a[d]

请注意,这不会打印最终的换行符。如果您需要; print ""在块的末尾添加一个:

END {for(i=0;i<10;i++) for(j=0;j<a[i];j++) printf "%d", i; print ""}

当然,结果是如此多余,以至于您可能更喜欢更紧凑的形式,例如,每个字符一行有两个字段:字符和出现次数:

awk 'BEGIN {FS=""}
  {for(i=1;i<=NF;i++) a[$i]++}
  END {for(i in a) printf "%s %d\n", i, a[i]}' file

刚刚在具有 1.4GB 输入的 3.6 GHz Intel Core i7 上测试了最后一个:2m38.480s。


推荐阅读