【问题标题】:Find the longest sublist查找最长的子列表
【发布时间】:2013-01-04 14:20:56
【问题描述】:

我有一个包含列表和子列表的文件,我想使用命令行工具提取最长的子列表。

文件示例:

* Item1
** SubItem1
** ...
** SubItemN

* Item2
** SubItem1
** ...
** SubItemN

* ...
** ...

* ItemN
** SubItem1
** ...
** SubItemN

我想知道这是否可以轻松完成,否则我将编写一个 Perl 脚本。

【问题讨论】:

  • 比 Perl 脚本更简单?我不这么认为。听起来像是 2-3 行 Perl。

标签: perl shell awk grep wc


【解决方案1】:

Perl 单行:

perl -00 -ne '$n=tr/\n/\n/; if ($n>$m) {$m=$n; $max=$_}; END {print $max}' file

只使用 bash:

max=0
while read bullet thingy; do
    case $bullet in
         "*") item=$thingy; count=0 ;;
        "**") ((count++)) ;;
          "") (( count > max )) && { max_item=$item; max=$count; } ;; 
    esac
done < <(cat file; echo)
echo $max_item $max

&lt;(cat file; echo)部分是为了保证文件最后一行后面有一个空行,这样最后的sublist group可以和max进行比较

这只会保持计数。将项目保存在最大的子列表中:

max=0
while read bullet thingy; do
    case $bullet in
         "*") item=$thingy; unset sublist; sublist=() ;;
        "**") sublist+=($thingy) ;;
          "") if (( ${#sublist[@]} > max )); then
                  max=${#sublist[@]}
                  max_item=$item
                  max_sublist=("${sublist[@]}")
              fi
              ;;
    esac
done < <(cat file; echo)
printf "%s\n" "$max_item" "${#max_sublist[@]}" "${max_sublist[@]}"

如果使用 sudo_O 的例子,这个输出

letters
6
a
b
b
d
e
f

【讨论】:

  • 它一次读取一个段落 (-00) -- 将每个段落存储在特殊变量 $_ 中。它计算段落中的换行数 (tr)。其余的,找到最大值,应该很明显。
  • @JohnJohnGa,我在评论中添加了一些链接以供进一步教育
【解决方案2】:
$ cat file    
* letters
** a
** b
** b
** d
** e
** f

* colors 
** red
** green
** blue

* numbers
** 1
** 2
** 3
** 4
** 5

通过使用tac 和使用awk 反转文件来显示每个子列表的长度:

$ tac file | awk '/^\*\*/{c++}/^\*[^*]/{print c,$2;c=0}'
5 numbers
3 colors
6 letters

仅打印最大子列表的长度:

$ tac file | awk '/^\*\*/{c++}/^\*[^*]/{if(c>m){m=c;l=$2}c=0}END{print m,l}'
6 letters

【讨论】:

  • awk:第 1 行:正则表达式编译失败(语法错误 ^* 或 ^+)^*[^*]
【解决方案3】:
cat file.txt | grep -nE "^\*[^\*].*" | cut -d ":" -f 1,1 | tee tmp | awk 'NR==1{s=$1;next}    {print $1-s;s=$1}' > tmp2
echo 0 >> tmp2
res=`paste tmp tmp2 | sort -nrk 2,2 | head -n 1`
line=`echo "$res" | cut -f 1,1`
ln=`echo "$res" | cut -f 2,2`
cat file.txt | tail -n +$line | head -n $ln
rm tmp tmp2

肯定有更短的解决方案:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 2021-09-02
    • 1970-01-01
    相关资源
    最近更新 更多