找出序号中的差距

时间:2013-04-07 20:42:02

标签: bash awk

如果这是一个简单的问题(或者比我想象的更复杂),我不会以此为生,请原谅我。我一直在挖掘档案,发现很多技巧很接近但是新手我不知道如何调整我的需求,或者他们超出了我的理解。

我有一些大型数据文件,我可以解析它们来生成一个主要是顺序的坐标列表

5
6
7
8
15
16
17
25
26
27

我想要的是间隙列表

1-4
9-14
18-24

我不知道 perl SQL 或任何花哨的东西,但我想我可以做一些可以减去下一个数字的东西。然后,我可以至少grep输出差异不是 1 -1 的输出,并使用它来获得差距。

6 个答案:

答案 0 :(得分:65)

使用

awk '$1!=p+1{print p+1"-"$1-1}{p=$1}' file.txt

解释

  • $1是当前输入行的第一列
  • p是最后一行的前一个值
  • 所以($1!=p+1)是一个条件:如果$1与之前的值+1不同,那么:
  • 此部分已执行:{print p+1 "-" $1-1}:打印上一个值+1,-字符和第一列+ 1
  • 每行都执行
  • {p=$1}p已分配给当前第1列

答案 1 :(得分:3)

Ruby答案

也许其他人可以为您提供您要求的Bash或Awk解决方案。但是,我认为任何基于shell的答案都可能对您的数据集非常本地化,而且不是很容易扩展。解决Ruby中的问题非常简单,并为您提供灵活的格式化和更多选项,以便在未来的其他方式操作数据集。 YMMV。

#!/usr/bin/env ruby

# You could read from a file if you prefer,
# but this is your provided corpus. 
nums = [5, 6, 7, 8, 15, 16, 17, 25, 26, 27]

# Find gaps between zero and first digit.
nums.unshift 0

# Create array of arrays containing missing digits.
missing_nums = nums.each_cons(2).map do |array|
                 (array.first.succ...array.last).to_a unless
                  array.first.succ == array.last
               end.compact
# => [[1, 2, 3, 4], [9, 10, 11, 12, 13, 14], [18, 19, 20, 21, 22, 23, 24]]

# Format the results any way you want.
puts missing_nums.map { |ary| "#{ary.first}-#{ary.last}" }

鉴于您当前的语料库,这会在标准输出上产生以下结果:

  

1-4
  9-14
  18-24

答案 2 :(得分:2)

只需记住上一个数字并验证当前的数字是前一个加号:

#! /bin/bash
previous=0
while read n ; do
    if (( n != previous + 1 )) ; then
        echo $(( previous + 1 ))-$(( n - 1 ))
    fi
    previous=$n
done

您可能需要添加一些检查以防止28-28等行出现单个数字空白。

答案 3 :(得分:2)

有趣的问题。

sputnick的awk单行很好。我不能写一个比他更简单的。我只是使用diff添加另一种方式:

 seq $(tail -1 file)|diff - file|grep -Po '.*(?=d)'

您的示例的输出将是:

1,4
9,14
18,24

我知道其中有逗号,而不是-。你可以用sed替换grep得到-,grep不能改变输入文本......但是想法是一样的。

希望它有所帮助。

答案 4 :(得分:0)

Perl解决方案类似于StardustOne的awk解决方案:

perl -ane 'if ($F[0] != $p+1) {printf "%d-%d\n",$p+1,$F[0]-1}; $p=$F[0]' file.txt

使用以下命令行选项:

  • -n循环输入文件的每一行,不自动打印每一行

  • -a autosplit模式 - 将输入行拆分为@F数组。默认为在空格上拆分。字段从0开始编制索引。

  • -e执行perl代码

答案 5 :(得分:0)

根据输入文件,使用文件旁边的numinterval utilpaste输出,然后将其与tr进行混合,{ {1}},xargssed

printf

gaps() { paste <(echo; numinterval "$1" | tr 1 '-' | tr -d '[02-9]') "$1" | tr -d '[:blank:]' | xargs echo | sed 's/ -/-/g;s/-[^ ]*-/-/g' | xargs printf "%s\n" ; } 的输出:

gaps file

工作原理。 5-8 15-17 25-27 的输出如下:

paste  <(echo; numinterval file) file

从那里我们主要替换第1列中的内容,并调整间距。 5 1 6 1 7 1 8 7 15 1 16 1 17 8 25 1 26 1 27 1替换,更高的数字被删除。使用-删除一些空格。使用单个连字符“ 5-8 ”替换“ 5-6-7-8 ”等连字符的运行,这就是输出。