在数字序列中搜索缺失的数字

在数字序列中搜索缺失的数字

所以我有一个包含大量信息的文件,每个信息“块”都有它自己的唯一标识符,如下所示:

“指数”:数字

在linux中使用以下命令后:

$ cat file | grep index

我得到这个结果:

"index": 1
"index": 2
"index": 3
...
"index": 10001

它们之间是一系列连续格式的数字。

那里的某个地方缺少一个号码,我正在尝试找出那个号码。

我尝试了几件事,但没有一个奏效。是否有另一个命令可以添加到它或者是否有更好的方法来搜索丢失的索​​引号?

答案1

您可以使用diff命令来获取文件与从 N 到 M 的数字序列之间的差异。该awk命令用于解析文本并仅获取数字:

diff --side-by-side --suppress-common-lines  <(awk '{print $2}' file.txt) <(seq 1 10001) | awk '{print $2}'

上面的代码将文件的编号与 from1到 的序列进行比较10001

为了更多功能性的实现此方法的方法是,您可以检测文件的最后一个数字(10001)并将其分配给一个变量:

max=$(tail -1 file.txt | awk '{print $2}')
diff --side-by-side --suppress-common-lines  <(awk '{print $2}' file.txt) <(seq 1 $max) | awk '{print $2}'

例如,有这样的:

文件.txt

"index": 1
"index": 5
"index": 8
"index": 9
"index": 10
"index": 12
"index": 13
"index": 15
max=$(tail -1 file.txt | awk '{print $2}')
diff --side-by-side --suppress-common-lines  <(awk '{print $2}' file.txt) <(seq 1 $max) | awk '{print $2}'

输出:

2
3
4
6
7
11
14

顺便说一句,如果您想以这种格式打印缺失值:"index": the_missing_number您可以更改最后一条awk print语句,如下所示:

diff --side-by-side --suppress-common-lines  <(awk '{print $2}' file.txt) <(seq 1 $max) | awk '{print "\"index\": "$2}'

答案2

从您的示例中,关于包含索引标签和整数的文件的两个重要假设:

"index": 1
"index": 2
"index": 3
...
"index": 10001

假设是:

  1. 从第一行到最后一行读取时,索引整数按升序排列。
  2. 一个或多个空格或制表符将"index":标签与索引整数分隔开。

只要两者都为真,这个小循环bash就可以输出缺失的数字(但请阅读代码后的警告)。带有索引标签和整数的文件被命名为indexes.txt

cur_idx=0
last_idx=0
while read label cur_idx; do
  (( last_idx != ( cur_idx - 1 ))) && echo $(( cur_idx - 1 ))
  last_idx=${cur_idx}
done < indexes.txt

该循环会记住最后看到的索引,并且在读取新索引行后,它将当前(新)索引[负1]与最后一个索引进行比较。当它们不相等时,会跳过索引并打印跳过的索引。

警告:

如果有两个或多个连续缺失的索引,则此循环将仅打印出第一个缺失的索引。它不会打印所有内容。
即,如果您有:

"index": 21
"index": 24

(缺少2223),循环将只打印22。但是,这将让您查看indexes.txt之后的文件21并查看跳过了多少数字。我从你的问题中得到的印象是只有一两个缺失的索引,所以这不应该妨碍你。

答案3

您可以使用简单的 grep/awk 语句来完成此操作。与 awk 行号 (NR) 不具有相同编号的第一行匹配索引,然后打印行号并退出。

grep index file | awk -F: '{ if (NR != $2 ) {print "missing " NR; exit;} }'

答案4

使用(以前称为 Perl_6)

~$ raku -e 'my @a; for lines() {@a.push: $/.Int if .match(/<?after \"index\"\: \s > \d+ /) };  \
            put ((1..10) (-) @a.Set).keys.sort;'  index.txt

#OR

~$ raku -e 'my @a; for lines() {@a.push: $0.Int if .match(/<?after \"index\"\: \s > (\d+) /) };  \
            put ((1..10) (-) @a.Set).keys.sort;'  index.txt

Raku 是 Perl 家族的一种编程语言。它于 2015 年发布为 Perl_6,并于 2019 年更名为 Raku。因此,您会在 Raku 中发现许多“Perl 主义”。

Raku 的一项有趣功能是集合语义。 Unicode 和 ASCII 运算符均可用。上面的代码中,ASCII(-)代表设置差异(非对称)。您还可以使用 Unicode:


SET MINUS
Unicode: U+2216, UTF-8: E2 88 96

示例输入(注意最大值为 100):

"index": 1
"index": 2
"index": 3
"index": 5
"index": 100

示例输出(两个代码示例):

4 6 7 8 9 10

警告:对称和非对称 Set 操作很容易混淆。例如,对于上面的代码,如果您颠倒集合的顺序并尝试 ASCII(^)或 Unicode 对称集差相反,您会看到很大的差异(用作1..99测试范围):

~$ cat index.txt | perl6 -e 'my @a = do for lines() {$/.Int if .match(/<?after \"index\"\: \s > \d+ /) }; put (@a.Set (-) (1..99)).keys.sort;'
100
~$ cat index.txt | perl6 -e 'my @a = do for lines() {$/.Int if .match(/<?after \"index\"\: \s > \d+ /) }; put (@a.Set (^) (1..99)).keys.sort;'
4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

https://docs.raku.org/language/setbagmix
https://raku.org

相关内容