按同一行上不同值之间的最大差异排序

时间:2014-02-24 23:33:44

标签: bash sorting

我有一个数据集,我需要做一些特定的排序。这是一个示例:

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脚本编写能力,所以我想我会转向互联网寻求帮助。非常感谢任何帮助。

4 个答案:

答案 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的新内容,因为版本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”是保存数据的任何文件。