किसी अन्य स्तंभ के मान के आधार पर डुप्लिकेट निकालें


9

मेरे पास निम्न फ़ाइल है:

AA,true
AA,false
BB,false
CC,false
BB,true
DD,true

मैं डुप्लिकेट देखने और स्तंभ मान के बराबर वाली रेखा को निकालने का प्रयास कर रहा हूं true

आउटपुट के रूप में यह होना चाहिए:

AA,false
BB,false
CC,false
DD,true

2
तो .. केवल रखें trueअगर यह पहले कॉलम का पहला उदाहरण है?
डोपघोटी

1
@ रोमेनपेरेक्रेस्ट संभवतः क्योंकि एक यूनीक प्रविष्टि है और "जैसा है वैसा ही छपा है"
जॉर्ज वासिलियो

@RomanPerekhrest क्योंकि डीडी, सच एक डुप्लिकेट नहीं है हमारे पास डीडी, झूठी के साथ एक और लाइन नहीं है।
हानी गोटेक

AA,true AA,false AA,false AA,falseइस मामले में क्या आउटपुट होना चाहिए? मैं समझता हूं, उस पंक्ति को केवल तभी हटाया जाना चाहिए जब वह डुप्लिकेट हो और trueउसी समय समाहित हो। सभी falseपंक्तियों को किसी भी मामले में अछूता रहना चाहिए। यही है, इस मामले में, केवल AA, trueहटा दिया जाएगा। लेकिन सभी उत्तर केवल एक पंक्ति छोड़ते हैं - AA,false। बस दिलचस्प :)
मिनीमेक्स

जवाबों:


9
awk -F, '$2 == "false" {data[$1]=$2 } $2=="true" { if ( data[$1]!="false" ) { data[$1]=$2 } } END { OFS=","; for (item in data) { print item,data[item] }}' input

स्पष्टीकरण के लिए स्क्रिप्ट को लंबवत रूप से विस्तारित करने के लिए:

BEGIN {
   FS=","         # Set the input separator; this is what -F, does.
}
$2 == "false" {    # For any line whose second field is "false", we
   data[$1]=$2     # will use that value no matter what.
}
$2=="true" {                    # For lines whose second field is "true",
   if ( data[$1]!="false" ) {   # only keep if if we haven't yet seen a
      data[$1]=$2               # "false"
   }
}
END {                           # Now that we have tabulated our data, we
   OFS=","                      # can print it out by iterating through 
   for (item in data) {         # the array we created.
      print item,data[item]
   }
}

@DopeGhoti अच्छी तरह से समझाया! आपने इस पर मेरा +1 प्राप्त कर लिया है।
वैलेंटाइन बजरमी

14

सरल संस्करण:

sort input.txt | awk -F, '!a[$1]++'

"असत्य" प्रकार "सत्य" से पहले वर्णानुक्रम में होता है और यहां अवाक कमांड केवल प्रत्येक विशिष्ट प्रथम फ़ील्ड मान के लिए पहली पंक्ति रखता है।

यदि आप "झूठे" के बजाय "सही" रखना चाहते हैं, तो इसे उल्टा कर दें, इसे उसी अवाक कमांड में पास करें, और बाद में इसे फिर से छांटें।


1
यदि -uविकल्प उपलब्ध है , तो भी,sort input.txt | sort -t, -u -k1,1
सुंदरजीप

2
@ सुदीप दो sortकॉल का उपयोग क्यों करते हैं? सिर्फ क्यों नहीं sort -ut, -k1,1 input.txt ?
terdon

2
@terdon क्योंकि -uडुप्लिकेट के बीच इनपुट फ़ाइल से मिली पहली पंक्ति को बनाए रखेगा ... दिए गए मामले के लिए, इनपुट को पहले -uलागू करने से पहले सॉर्ट करना होगा ... पूर्व के लिए: AA,trueबजाय मुद्रित किया जाएगा AA,falseक्योंकि यह पहले दिए गए नमूने में दिखाई देता है। यही कारण है कि awk -F, '!a[$1]++'अकेले ही इस समस्या का समाधान नहीं करेगा
सुदीप

5
perl -F, -lane '
   exists $h{$F[0]} or $h[$h{$F[0]}=@h]=$_;
   $h=$_; /,false$/ or $_=$h for $h[$h{$F[0]}];
   END{ print for @h; }
' duplicates.file

डेटा संरचनाएं:

  • हैश %hजिनकी कुंजियाँ पहले फ़ील्ड्स हैं (AAA, BBB, CCC, इत्यादि) और संबंधित मान संख्याएँ हैं जिसमें उस क्रम को बताया गया है जिसमें कुंजियाँ मिली थीं। इस प्रकार, जैसे, कुंजी एएए => 0, कुंजी बीबीबी => 1, कुंजी सीसीसी => 2।
  • सरणी @hजिसके तत्व मुद्रण के क्रम में निहित रेखाएँ हैं। इसलिए यदि डेटा में सत्य और असत्य दोनों पाए जाते हैं, तो गलत मान सरणी में जाएगा। OTW, यदि एक प्रकार का डेटा है, तो वह मौजूद होगा।

एक अन्य तरीका GNU sed का उपयोग कर रहा है:

sed -Ee '
   G
   /^([^,]*),(false|true)\n(.*\n)?\1,\2(\n|$)/ba
   /^([^,]*)(,true)\n(.*\n)?\1,false(\n|$)/ba
   /^([^,]*)(,false)\n((.*\n)?)\1,true(\n|$)/{
      s//\3\1\2\5/;h;ba
   }
   s/([^\n]*)\n(.*)$/\2\n\1/;s/^\n*//
   h;:a;$!d;g
' duplicates.file

FWIW, उपरोक्त GNU- सेड कोड के लिए POSIX समकक्ष कोड नीचे सूचीबद्ध है:

sed -e '
   G

   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false$/ba
   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false\n/ba

   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true$/{
      s//\3\1\2/
      h
      ba
   }
   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true\n/{
      s//\3\1\2\n/
      h
      ba
   }

   y/\n_/_\n/
   s/\([^_]*\)_\(.*\)$/\2_\1/;s/^_*//
   y/\n_/_\n/

   h;:a;$!d;g
' duplicates.file

व्याख्या

  • इस पद्धति में हम परिणाम को अंत में होल्ड स्पेस में प्रिंट करने के लिए स्टोर करते हैं।
  • पढ़ी गई प्रत्येक पंक्ति के लिए, हम होल्ड स्पेस की मौजूदा स्थिति की वर्तमान लाइन की वर्तमान स्थिति की जांच के लिए पैटर्न स्पेस को पकड़ते हैं।
  • अब इस तुलना के दौरान 5 चीजें हो सकती हैं:
    • a) करेंट लाइन कहीं न कहीं होल्ड लाइन में मौजूद है और गलत: गलत है।
      • [क्रिया] चूंकि एक ही झूठी स्थिति पाई जाती है, तो कुछ भी न करें।
    • बी) वर्तमान लाइन कहीं न कहीं होल्ड लाइन और सच में मेल खाती है: सच।
      • [क्रिया] चूँकि वही सच्ची अवस्था पाई जाती है, तो कुछ भी न करें।
    • ग) वर्तमान लाइन कहीं न कहीं होल्ड लाइन और सच में मेल खाती है: असत्य।
      • [कार्य] चूंकि एक झूठी स्थिति पहले से मौजूद है, इसलिए कुछ भी न करें।
    • d) वर्तमान लाइन कहीं न कहीं होल्ड लाइन में निहित है और गलत: सच है।
      • [कार्य] इसमें कुछ काम शामिल हैं, जिसमें हमें झूठी रेखा को उसी स्थान पर बदलने की आवश्यकता है जहां सही स्थित है।
    • ई) वर्तमान लाइन होल्ड लाइन में कहीं भी मेल नहीं खाती है।
      • [क्रिया] वर्तमान रेखा को अंत तक ले जाएं।

परिणाम

AA,false
BB,false
CC,false
DD,true

3

प्रत्येक इनपुट लाइन के लिए, साहचर्य सरणी में दूसरे फ़ील्ड का मान संग्रहीत करें a(पहले फ़ील्ड को सरणी की कुंजी के रूप में उपयोग करके) केवल तभी जब हमने falseउस कुंजी के लिए मान पहले से संग्रहीत नहीं किया है । ,इनपुट और आउटपुट फील्ड सेपरेटर दोनों के लिए उपयोग करें । सभी इनपुट लाइनों को पढ़ने के बाद सरणी को प्रिंट करें।

$ awk -F, -v OFS=, 'a[$1] != "false" { a[$1] = $2 };
                    END { for (i in a) {print i,a[i]} }' truefalse.txt
AA,false
BB,false
CC,false
DD,true

इस और डोपघोटी के संस्करण के बीच महत्वपूर्ण अंतर यह है कि यह संस्करण सभी के मूल्य के बारे में परवाह नहीं करता है $2, यह केवल मूल्य के बारे में परवाह करता है, यदि कोई है, तो a[$1]


1

दो-पास sortसमाधान

sort -k1,1 -k2,2 -t, file | sort -k1,1 -t, -u

सामान्य फ़ील्ड मान साझा करने वाले रिकॉर्ड्स के प्रत्येक ब्लॉक के लिए पूर्व रिकॉर्ड्स के साथ sortफ़ील्ड द्वारा रिकॉर्ड्स को पहले पास करें । दूसरा दर्रा क्षेत्र शिष्टाचार के भीतर प्रत्येक अलग मूल्य के लिए एक रिकॉर्ड प्राप्त करने के लिए स्थापित किया गया है । चूंकि स्थिर छंटाई का मतलब है, इस तरह से प्राप्त किया गया एक रिकॉर्ड फ़ील्ड के भीतर प्रत्येक विशिष्ट मूल्य के लिए पहला रिकॉर्ड है - जो कि पहले पास द्वारा किए गए काम के कारण दूसरे क्षेत्र में रिकॉर्ड है1falsetrue1sort1-u-u1falsesort

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.