3

次のような大規模なデータセットがあります。

5 6 5 6 3 5
2 5 3 7 1 6
4 8 1 8 6 9
1 5 2 9 4 5

すべての行について、2 番目から 1 番目のフィールドを減算し、4 番目から 3 番目のフィールドを減算して、フィールドの数を増やします (常に偶数)。次に、すべてのペアとの差が特定の制限 (たとえば 2) を超えている行を報告したいと思います。また、次善の行、つまり、1 つのペアごとの比較が制限を満たしていないが、他のすべてのペアが制限を満たしている行もレポートできるはずです。

上記の例から、制限を 2 に設定すると、出力ファイルには最適な行が含まれているはずです。

2 5 3 7 1 6    # because (5-2), (7-3), (6-1) are all > 2
4 8 1 8 6 9    # because (8-4), (8-1), (9-6) are all > 2 

次善の行

1 5 2 9 4 5    # because except (5-4), both (5-1) and (9-2) are > 2

私の現在のアプローチは、すべての行を読み取り、各フィールドを変数として保存し、減算を行うことです。しかし、私はさらに進む方法がわかりません。

ありがとう、

4

5 に答える 5

3

これを行うためのbash方法は次のとおりです。

#!/bin/bash

threshold=$1
shift
file="$@"

a=($(cat "$file"))
b=$(( ${#a[@]}/$(cat "$file" | wc -l) ))

for ((r=0; r<${#a[@]}/b; r++)); do
    br=$((b*r))
    for ((c=0; c<b; c+=2)); do

        if [[ $(( ${a[br + c+1]} - ${a[br + c]} )) < $threshold ]]; then
            break; fi

        if [[ $((c+2)) == $b ]]; then
            echo ${a[@]:$br:$b}; fi

    done
done

使用法:

$ ./script.sh 2 yourFile.txt
2 5 3 7 1 6
4 8 1 8 6 9

この出力は、簡単にリダイレクトできます。

$ ./script.sh 2 yourFile.txt > output.txt

注:各行の間に空の行があると、これは正しく機能しません...しかし、上記の方法でうまくいくと確信しています。

于 2012-11-09T18:27:17.277 に答える
3

"best" 行をファイル "best" に出力し、"nextbest" 行をファイル "nextbest" に出力します。

awk '
{
        fail_count=0
        for (i=1; i<NF; i+=2){
                if ( ($(i+1) - $i) <= threshold )
                        fail_count++
        }
        if (fail_count == 0)
                print $0 > "best"
        else if (fail_count == 1)
                print $0 > "nextbest"
}
' threshold=2 inputfile

かなり簡単なもの。

  1. 一度に 2 つのフィールドをループします。
  2. (次のフィールド - 現在のフィールド) が を超えない場合threshold、インクリメントfail_count
  3. その行fail_countがゼロの場合、それは「最良の」行に属していることを意味します。

    それ以外の場合、その行fail_countが 1 つである場合、それは「次善の」行に属します。

于 2012-11-10T09:08:07.647 に答える
1

さらに別の bash バージョン:

最初の acheck functionは結果コードのみを返します:

function getLimit() {
    local pairs=0 count=0 limit=$1 wantdiff=$2
    shift 2
    while [ "$1" ] ;do
        [ $(( $2-$1 )) -ge $limit ] && : $((count++))
        : $((pairs++))
        shift 2
      done
    test $((pairs-count)) -eq $wantdiff
}

今より:

while read line ;do getLimit 2 0 $line && echo $line;done <file
2 5 3 7 1 6
4 8 1 8 6 9

while read line ;do getLimit 2 1 $line && echo $line;done <file
1 5 2 9 4 5
于 2012-11-10T13:17:04.570 に答える
1

私はおそらくbashでそれをしないでしょう。個人的には、Python でそれを行いたいと思います。これは、一般に、これらの小さくて簡単なスクリプトに適しています。

テキスト ファイルにデータがある場合は、そのデータを行のリストとして Python に取り込む方法について、こちらを参照してください。次に、for ループを使用して各行を処理できます。

threshold = 2
results = []
for line in content:
    numbers = [int(n) for n in line.split()] # Split it into a list of numbers
    pairs = zip(numbers[::2],numbers[1::2]) # Pair up the numbers two and two.
    result = [abs(y - x) for (x,y) in pairs] # Subtract the first number in each pair from the second.
    if sum(result) > threshold:
        results.append(numbers)
于 2012-11-09T17:30:43.617 に答える