我有一个数据集,我需要做一些特定的排序。这是一个示例:
43 37 1512 1591 59 2819 97 1546 1435
43 37 1512 1591 59 2819 98 331 1539
43 37 1512 1591 59 2819 99 67 633
43 67 2772 2881 37 10189 51 2000 806
43 67 2772 2881 37 10189 52 228 1315
43 67 2772 2881 37 10189 61 2657 718
43 67 2772 2881 37 10189 62 893 1818
43 67 2772 2881 37 10189 63 1553 1293
43 67 2772 2881 47 8375 74 95 185
43 67 2772 2881 47 8375 75 1919 862
43 67 2772 2881 47 8375 79 1425 651
31 61 1800 1891 47 3983 86 137 300
31 61 1800 1891 47 3983 87 67 470
31 61 1800 1891 47 3983 88 1711 285
对于每一行,我需要将值从最小值排序到最长值,然后找出每个值之间的差异。然后,我需要找到排序值之间的最小差异,并将该数字附加到行的末尾。最后(这里是棘手的部分),我需要以数字方式显示“最小差异”列中的所有行,但其他值必须按原始顺序显示。
例如,使用数据集的最后一行,脚本必须执行以下操作:
开始:
31 61 1800 1891 47 3983 88 1711 285
排序:
31 47 61 88 285 1711 1800 1891 3983
每个#之间的差异
. 16 14 27 197 1426 89 91 2092
最小的差异:
14
在自己的列中预先添加ORIGINAL LINE的最小差异:
14 31 61 1800 1891 47 3983 88 1711 285
最后,根据新添加的“最小差异”列对所有行进行排序。我不关心列之间的空白量,它可以根据需要波动以使脚本更简单。
这有点超出了我的bash脚本编写能力,所以我想我会转向互联网寻求帮助。非常感谢任何帮助。
答案 0 :(得分:5)
我会选择Perl:
perl -lane '
BEGIN { $,=" "; sub numeric {$a <=> $b} }
@sorted = sort numeric @F;
@diffs = map {$sorted[$_] - $sorted[$_-1]} 1..$#sorted;
$min_diff = ( sort numeric @diffs )[0];
print $min_diff, @F
' filename | sort -n
4 43 67 2772 2881 37 10189 63 1553 1293
4 43 67 2772 2881 47 8375 74 95 185
4 43 67 2772 2881 47 8375 75 1919 862
4 43 67 2772 2881 47 8375 79 1425 651
5 43 67 2772 2881 37 10189 62 893 1818
6 31 61 1800 1891 47 3983 87 67 470
6 43 37 1512 1591 59 2819 97 1546 1435
6 43 37 1512 1591 59 2819 98 331 1539
6 43 37 1512 1591 59 2819 99 67 633
6 43 67 2772 2881 37 10189 51 2000 806
6 43 67 2772 2881 37 10189 52 228 1315
6 43 67 2772 2881 37 10189 61 2657 718
14 31 61 1800 1891 47 3983 86 137 300
14 31 61 1800 1891 47 3983 88 1711 285
Ruby更短:
ruby -ane '
min_diff = $F.map(&:to_i).sort.each_cons(2).map {|a,b| b-a}.sort.min
puts [min_diff, $F].join " "
'
答案 1 :(得分:3)
有点满口,但我认为这或多或少是你所需要的:
#!/bin/bash
mapfile -t a < "$1" # read file into an array
for i in ${!a[@]}; do # loop over the array
p=0 # "previous" number
# convert line of numbers to one number per line, then sort and loop
< <(for n in $(sort -n <<< "${a[i]//[[:blank:]]/$'\n'}" ); do
if [ $p -gt 0 ]; then # if not 1st number
echo $((n-p)) # calculate difference
fi
p=$n # save number for next calc
done | sort -n) read d _ # get smallest diff from process substitution
echo "$d ${a[i]}" # paste difference at the start of the line
done | sort -n # sort by smallest difference
另存为脚本,chmod +x
并运行:
$ ./nsort.sh input.txt 4 43 67 2772 2881 37 10189 63 1553 1293 4 43 67 2772 2881 47 8375 74 95 185 4 43 67 2772 2881 47 8375 75 1919 862 4 43 67 2772 2881 47 8375 79 1425 651 5 43 67 2772 2881 37 10189 62 893 1818 6 31 61 1800 1891 47 3983 87 67 470 6 43 37 1512 1591 59 2819 97 1546 1435 6 43 37 1512 1591 59 2819 98 331 1539 6 43 37 1512 1591 59 2819 99 67 633 6 43 67 2772 2881 37 10189 51 2000 806 6 43 67 2772 2881 37 10189 52 228 1315 6 43 67 2772 2881 37 10189 61 2657 718 14 31 61 1800 1891 47 3983 86 137 300 14 31 61 1800 1891 47 3983 88 1711 285 $
注意mapfile
是bash的新内容,因为版本4.0如果您有旧版本,则需要while read
循环才能将文件读入数组。
通常你应该对你所尝试的内容有所了解,而不是指望SO社区为你编写脚本。
答案 2 :(得分:2)
使用Gnu Awk第4版:
awk -f a.awk file
其中a.awk
是:
BEGIN {
PROCINFO["sorted_in"]="@val_num_asc"
}
{
for (i=1; i<=NF; i++)
a[i]=$i
j=0;
for (i in a) {
j++;
if (j>1) {
d=a[i]-prev;
if (j==2) mind=d;
else if (d<mind) mind=d;
}
prev=a[i]
}
b[FNR]=(mind OFS $0)
c[FNR]=mind
}
END {
for (i in c)
print b[i]
}
输出:
4 43 67 2772 2881 37 10189 63 1553 1293
4 43 67 2772 2881 47 8375 74 95 185
4 43 67 2772 2881 47 8375 75 1919 862
4 43 67 2772 2881 47 8375 79 1425 651
5 43 67 2772 2881 37 10189 62 893 1818
6 43 37 1512 1591 59 2819 97 1546 1435
6 43 37 1512 1591 59 2819 98 331 1539
6 43 37 1512 1591 59 2819 99 67 633
6 43 67 2772 2881 37 10189 51 2000 806
6 43 67 2772 2881 37 10189 52 228 1315
6 43 67 2772 2881 37 10189 61 2657 718
6 31 61 1800 1891 47 3983 87 67 470
14 31 61 1800 1891 47 3983 86 137 300
14 31 61 1800 1891 47 3983 88 1711 285
答案 3 :(得分:1)
在python的一行中:
In [2]: sorted([[max([l[n-1]-l[n] for n in range(len(l))])]+l for l in [[int(i) for i in line.split()] for line in open("file.tsv", 'r').readlines()], key=lambda line: line[0])
其中“file.tsv”是保存数据的任何文件。