对文本文件中的所有字符进行操作的更快方法
Faster method to operate on all characters in a text file
我想在一个很长的字符串上执行一个任务,我认为我需要对每个字符单独进行操作。在这样做之前,我首先尝试 建立访问所有这些字符所需时间的基线 。
我打算使用的输入是一个文本文件,其中单行包含一个由数字组成的单词。
下面的代码是我迄今为止最好的尝试,是否有更快的方法逐个访问字符串中的所有字符?
function handle_split() {
split=
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"
GNU 或 BSD awk
可能是一个不错的选择:
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
应该是你想要的。解释:BEGIN
块中的 FS=""
表示文件中的每个字符都是一个单独的字段。 {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
刚刚在 3.6 GHz Intel Core i7 上测试了最后一个,输入为 1.4GB:2m38.480s。
我想在一个很长的字符串上执行一个任务,我认为我需要对每个字符单独进行操作。在这样做之前,我首先尝试 建立访问所有这些字符所需时间的基线 。
我打算使用的输入是一个文本文件,其中单行包含一个由数字组成的单词。
下面的代码是我迄今为止最好的尝试,是否有更快的方法逐个访问字符串中的所有字符?
function handle_split() {
split=
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"
GNU 或 BSD awk
可能是一个不错的选择:
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
应该是你想要的。解释:BEGIN
块中的 FS=""
表示文件中的每个字符都是一个单独的字段。 {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
刚刚在 3.6 GHz Intel Core i7 上测试了最后一个,输入为 1.4GB:2m38.480s。