2016-12-28 80 views
0

我輸入文件如下減去值

100A 2000 
100B 150 
100C 800 
100A 1000 
100B 100 
100C 300 

我想減去第2列值在列中的每個uniq的值1 所以出來放應該像

100A 1000 
100B 50 
100C 500 

我已經試過

awk '{if(!a[$1])a[$1]=$2; else a[$1]=$2-a[$1]}END{ for(i in a)print i" " a[i]}' file 

但放出來是:

100A 0 
100B 0 
100C 0 

請指教

+0

如果第一列中的值重複多次,會發生什麼? – ghoti

+0

在這種情況下,我想採取第一次和最後一次發生 – Vicky

+0

發佈的解決方案都不會這樣做,他們所做的只是爲您提供的2入口示例(除了我的所有內容之外,不必要地將數據的一半保存在數組中然後以隨機順序產生輸出,而不是嚴格按照鍵值讀取的順序進行輸出,這可能或可能不合意)。 –

回答

2

這麼多的(輕微)的變化同一主題。

awk ' 
    !($1 in a) {a[$1]=$2; next} 
    {a[$1]-=$2} 
    END {for (i in a) printf "%s %d\n",i,a[i]} 
' input.txt 

如果您願意,可將其疊加爲一行。

請記住,awk結構由多個condition { statement }對組成,因此您可以比使用if..else更優雅地表達您的需求。 (並不是說這裏就是這種情況 - 這是一個足夠簡單的awk腳本,它可能並不重要,除非你是一個純粹主義者。])

另外,要小心測試值的方式,已經在你的if的條件下完成了這個問題。請注意,a[$1]測試該數組索引處的值是否爲非零值如果先前不存在,則會使索引存在空值。如果您想檢查索引是否存在,請使用$1 in a


更新基於對您的問題評論...

如果你想減去從第一最後,忽略之間的,那麼你需要保持記錄你的第一個和你的最後一個。像這樣的東西可能就足夠了。

awk ' 
    !($1 in a){a[$1]=$2;next} 
    {b[$1]=$2} 
    END {for(i in b)if(i in a)print i,a[i]-b[i]} 
' input.txt 

請注意,正如埃德提到的,這會產生隨機順序的輸出。如果你想要輸出的順序,你需要一個額外的數組來跟蹤訂單。例如,這將使用順序的項目,首先看出:

awk ' 
    !($1 in a) { 
    a[$1]=$2; 
    o[++n]=$1; 
    next 
    } 
    { 
    b[$1]=$2 
    } 
    END { 
    for (n=1;n<=length(o);n++) 
     print o[n],a[o[n]]-b[o[n]] 
    } 
' i 

注意,所使用的length()函數來確定數組中元素的數目是不普遍之中AWK的方言,但它確實在兩個工作gawk和one-true-awk(用於FreeBSD等)。

+0

我同意,但是當索引不存在時,我已經賦值$ [1] = $ 2,那麼我的解決方案有什麼問題? – Vicky

+0

您的測試是'if(!a [$ 1])',它不會測試不存在,它會導致索引存在(如果尚未存在)並測試值爲零。我不知道爲什麼你會得到你在問題中提到的結果,但是你已經減少了你的減法。你從第一個減去第二個值,所以當我運行示例代碼時,我會看到負數(1000 - 2000,100 - 150,300 - 800)。 – ghoti

+0

他們可能是負面的,因爲我必須找到整數差異,我只是意識到我的解決方案也在工作,並且我的解決方案沒有任何問題我只是用錯誤的輸入文件運行它 – Vicky

1

這AWK的一行這項工作:

awk '{if($1 in a)a[$1]=a[$1]-$2;else a[$1]=$2} 
     END{for(x in a) print x, a[x]}' file 
+0

使用if/else而不是awk與'condition {statement}'構造提供的隱式結構有什麼好處嗎? – ghoti

+0

@ghoti我覺得if/else是明確的 – Kent

0

您可以使用此awk

awk 'a[$1]{a[$1]=a[$1]-$2; next} {a[$1]=$2} END{for(v in a){print v, a[v]}}' file 
1

在awk中。使用條件運算符值配售/減法,以保持緊:

$ awk '{ a[$1]+=($1 in a?-$2:$2) } END{ for(i in a)print i, a[i] }' file 
100A 1000 
100B 50 
100C 500 

解釋:

{ 
    a[$1]+=($1 in a?-$2:$2) # if $1 in a already, subtract from it 
           # otherwise add value to it 
} 
END { 
    for(i in a)    # go thru all a 
     print i, a[i]   # and print keys and values 
} 
1

給你提供的樣品輸入,所有你需要的是:

$ awk '$1 in a{print $1, a[$1]-$2} {a[$1]=$2}' file 
100A 1000 
100B 50 
100C 500 

如果是這樣的不是所有你需要的,然後提供更真實的代表性樣本輸入/輸出,包括那些不夠好的情況。

+0

感謝埃德工作,這是一種方式來實現,如果-else在awk的條件塊中執行{print $ 1,a [$ 1] - $ 2},當$ 1中a評估爲true且{a [$ 1] = $ 2}當其他人執行1美元時評估爲假? – Vicky

+0

不,因爲還有其他的東西,你可以在第一個'}之前插入'; next'。現在分配發生在每一行,它只是在功能上無關緊要。 –