2016-04-10 8 views
1

Girdi verileri aşağıdaki 2. sütun göre sıralanır: Örnek bulguları, istenen çıkışı ileBaskı awk çiftler olarak belirli bir sütun göre belirli bir değer aralığı içinde olan tüm satırları

1 100 
1 101 
1 200 
3 360 
4 800 
4 950 
4 952 

olup:

1 200 3 360 
4 800 4 950 
4 800 4 952 

Yani, sütun 2'de değerler aralıkta olan satırlar varsa: value2, değer1 + 100'den büyükse & & value2 değeri1 + 200'den küçüktür.

girişimim oldu: karşılaştırmalar için değişkenlere önceki hattı ve önceki hat sütun 2 kaydeder

awk 'BEGIN{FS="\t"; PREVLOC=$2; PREVLINE=$0}{ if($2>PREVLOC+200 || $2<PREVLOC+100 {PREVLOC=$2; PREVLINE=$0;} else {print PREVLINE"\t"$0; PREVLOC=$2; PREVLINE=$0;} }' inputfile 

. Ancak, her durumda çalışmaz. Örnek verilerle, son çifti basmayacaktı. Ayrıca, ikinci sütun değerinin ör. 890.

Şu anda, birlikte bash tamamen farklı bir şekilde problemini çözdük:

`while read var1 var2; do stuff with vars in awk; done<inputfile` 

Ama çok yavaş. Herhangi bir yardım çok takdir edilmektedir.

cevap

1

Hala bir O(n^2) algoritması olduğu için bunun sizin için ne kadar iyi bir gelişme olacağını bilmiyorum, ama hepsi beceriksiz ve denemeye değer.

İki geçiş vardır. NR==FNR bloğu ilk geçiştir ve tüm dosyayı belleğe okur (dosya çok büyükse başka olası bir sorun ve performans konusunda endişeleniyorsanız oldukça büyük olduğunu tahmin ediyorum). Her satır için test edilecek aralığı ikinci geçişte saklıyoruz.

İkinci geçiş, satır satır ilerliyor ve koşulla eşleşenleri bulmak için her bir dizi aralık için tarama yapıyor.

Gösterildiği gibi awk çağrılırken giriş dosyasına iki kez giriş dosyasını sağlamanız gerektiğine dikkat edin.

$ cat input.txt 
1 100 
1 101 
1 200 
3 360 
4 800 
4 950 
4 952 

$ cat b.awk 
# first pass, load array with ranges 
NR==FNR {range[$0] = ($2 + 100) ":" ($2 + 200); next} 

# Here we process the file for the second time, looping through 
# all ranges for every line of input 
{ 
    for (i in range) { 
     split(range[i], r, ":") 
     if ($2 > r[1] && $2 < r[2]) { 
      print i, $0 
     } 
    } 
} 

$ awk -f b.awk input.txt input.txt 
1 200 3 360 
4 800 4 950 
4 800 4 952 
+0

Merhaba, çok teşekkürler. Tam olarak aradığım şey bu. Dosyalarımın her biri 100 k satıra sahiptir ve bunların 1000'lerine kadar olabilir (bunlar paralel olarak işlenir). Gerçek veriler daha birçok alanda daha karmaşıktır. Verilerle uğraşmak için geldiğim tek diğer yol, tüm olası çiftleri birleştirmek ve ardından awk, örn. örnek verilerle birlikte -1 -1 -2 1 -t $ '\ t' <(awk '{print 1 "\ t" $ 0}' inputfile) <(awk '{print 1 "\ t" $ 0} "inputfile) | awk 'BEGIN {OFS = FS = "\ t"} {if (5 $> 3 + 100 && 5 $ <3 $ + 200) 2 $ 3, $ 4, $ 5, $ 5}' ' – 5heikki

+0

Harika !, yararlıdır. Http://backreference.org/2010/02/10/idiomatic-awk/ adresindeki "İki dosya işleme" bölümü, bu tür kendi kendine katılma sorunları için awk kullanmanın bu yolunda daha fazla açıklama sağlar (nerede Söz konusu iki dosya aynı dosyadır). – jas