Поиск пробелов последовательных номеров
Я не делаю этого для жизни, поэтому простите меня, если это простой вопрос (или более сложный, чем я думаю). Я копал в архивах и нашел множество советов, которые близки, но являюсь новичком. Я не уверен, как подстраиваться под мои потребности, или они намного превосходят мое понимание.
У меня есть несколько больших файлов данных, которые я могу проанализировать для создания списка координат, которые в основном являются последовательными
5
6
7
8
15
16
17
25
26
27
То, что я хочу, это список пробелов
1-4
9-14
18-24
Я не знаю perl, SQL или что-то необычное, но думал, что смогу сделать что-то, что вычитает одно число из следующего. Я мог бы по крайней мере grep вывести, где разница не была 1 или -1 и работать с этим, чтобы получить пробелы.
Ответы
Ответ 1
С awk:
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-му столбцу
Ответ 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
Ответ на Ruby
Возможно, кто-то еще может предоставить вам решение Bash или Awk, о котором вы просили. Тем не менее, я думаю, что любой ответ на основе оболочки, скорее всего, будет крайне локализован для вашего набора данных и не очень расширяем. Решение проблемы в 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
Ответ 4
интересный вопрос.
sputnick awk one-liner хорош. Я не могу написать более простой, чем его. Я просто добавляю другой способ, используя diff:
seq $(tail -1 file)|diff - file|grep -Po '.*(?=d)'
вывод с вашим примером будет:
1,4
9,14
18,24
Я знал, что в нем есть запятая вместо -
. вы можете заменить grep на sed, чтобы получить -
, grep не может изменить текст ввода... но идея такая же.
надеюсь, что это поможет.
Ответ 5
Решение Perl аналогично решению awk от StardustOne:
perl -ane 'if ($F[0] != $p+1) {printf "%d-%d\n",$p+1,$F[0]-1}; $p=$F[0]' file.txt
Эти параметры командной строки используются:
-
-n
перемещаться по каждой строке входного файла, не печатать автоматически каждую строку
-
-a
режим автосплит - разделение входных строк на массив @F. По умолчанию разбивается на пробелы. Поля индексируются начиная с 0.
-
-e
выполнить код perl