【问题标题】:bash script: How to append characters at the end of a string efficiently (O(1))bash 脚本:如何有效地在字符串末尾追加字符 (O(1))
【发布时间】:2013-10-03 02:59:38
【问题描述】:

简单的问题:我有一个包含 n 个条目的数组 A,每个条目包含一个字符。我想要 以一种有效的方式从这个数组创建相应的字符串 S,即在 O(n) 时间内,不使用外部命令,只需 bash 代码和 bash 内置函数。

这种明显的方式...

func_slow ()
{ 
 local numel=${#A[*]}
 for ((i=0; i < numel ; i++))
 do
    S=${S}${A[$i]}   
 done
}

使用 bash 效率不高。这是 O(n^2) 时间,因为“追加”操作 S=${S}${A[$i]} 不需要 O(1) 时间最坏的情况(甚至 O(1) 时间摊销,这足以保证整体 O(n) 时间)。每次都需要 O(#S) (显然它通过复制 ${S} 和 ${A[$i]} 来生成新字符串 S)。 我能在 O(n) 时间内(无需外部命令)找到解决此问题的唯一方法是定义此函数

func_fast ()
{
 local numel=${#A[*]}
 for ((i=0; i < numel ; i++))
 do
    echo -n "${A[$i]}"
 done
}

然后像这样使用它

S=`func_fast`

这需要 O(n) 时间,它只使用 bash 代码和 bash 内置函数。使用有效的附加运算符(允许 func_slow 在 O(n) 时间内运行)同时仍然保留 O(1) 时间直接访问字符串的每个位置,实现(在语言的解释器中)字符串非常简单从算法的角度来看,我想知道我是否缺少一些特殊的高效 bash 字符串运算符。

【问题讨论】:

    标签: string performance bash append


    【解决方案1】:

    如果您想进行就地编辑,在末尾添加文本,您可以这样做:

    sed -ie 's/$/WHATEVER/g' FILENAME
    

    或者,在开头添加文本:

    sed -ie 's/^/WHATEVER/g' FILENAME
    

    特殊字符必须通过\ 转义。正则表达式备忘单是您最好的朋友。

    【讨论】:

    • 这根本不能回答问题!
    【解决方案2】:

    使用 IFS 进行数组合并:

    IFS= eval 'S="${A[*]}"'
    

    另外,如果您要将字符串附加到变量,只需使用以下形式:

    S+="another"
    

    另一种快速的方法是使用 printf:

    printf -v S '%s' "${A[@]}"
    

    添加一些基准。使用具有 100000 个整数元素的数组:

    time printf -v X '%s' "${A[@]}"
    
    real    0m0.481s
    user    0m0.474s
    sys     0m0.004s
    
    time IFS= eval 'X="${A[*]}"'
    
    real    0m0.107s
    user    0m0.106s
    sys     0m0.000s
    
    X=''; L=${#A[@]}; time for (( I = 0; I < L; ++I )); do X+=${A[I]}; done
    
    real    0m24.469s
    user    0m24.351s
    sys     0m0.074s
    

    【讨论】:

    • 所以我猜没有有效的附加运算符(+= 似乎和 S=${S}${A[$i]} 一样慢)。无论如何,其他两个是很好的答案(IFS 对我来说看起来很奇特:))
    • @terr 至少使用 IFS 方法,您可以选择您喜欢的分隔符 :) 顺便说一下,使用 eval 是可选的,但要使其有效,应该在解析行之前设置 IFS。所以你也可以像IFS=; X="${A[*]}" 那样做。但这将永久设置 IFS,因此您必须将其设置回默认值以免影响其他命令:IFS=$' \t\n'
    【解决方案3】:

    不确定计算复杂度,但这是可行的:

    t=${A[@]}
    S=${t// /}
    

    【讨论】:

    • 嗯..它对我不起作用。所以 S=${t// /} 从 t 中删除空格(它用空替换它们),对吗?不确定 ${A[@]} 是什么......只有当 A 已经是一个字符串时,这种表示法才适用于我。
    • ${A[@]} 本质上与${A[*]} 相同,只是在双引号中时不同。双引号时,* 使用 IFS 的第一个字符作为分隔符。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 2017-08-02
    • 2011-09-16
    • 1970-01-01
    相关资源
    最近更新 更多