জোড়া নকল লাইন মুছবেন?


16

আমি আজ এই ব্যবহারের মুখোমুখি হয়েছি। এটা প্রথম নজরে সহজ মনে হলেও নিয়ে তুচ্ছ sort, uniq, sedএবং awkজানা যায় যে এটা nontrivial আছে।

আমি কীভাবে সমস্ত জোড়া নকল লাইন মুছতে পারি ? অন্য কথায়, যদি কোনও প্রদত্ত লাইনের ডুপ্লিকেটগুলির একটিও সংখ্যা থাকে তবে সেগুলি সমস্ত মুছুন; যদি সদৃশ লাইনগুলির একটি বিজোড় সংখ্যা থাকে তবে একটি ব্যতীত সমস্ত মুছুন। (সাজানো ইনপুট ধরে নেওয়া যেতে পারে))

একটি পরিষ্কার মার্জিত সমাধান পছন্দনীয়।

উদাহরণ ইনপুট:

a
a
a
b
b
c
c
c
c
d
d
d
d
d
e

উদাহরণ আউটপুট:

a
d
e

উত্তর:


6

আমি sedএই প্রশ্নটি পোস্ট করার দীর্ঘ পরে উত্তরটি নিয়ে কাজ করেছি; অন্য কেউ এখনও sedঅবধি ব্যবহার করেন নি এটি এখানে:

sed '$!N;/^\(.*\)\n\1$/d;P;D'

আরও সাধারণ সমস্যা নিয়ে একটু খেলা (তিনটির সেটে লাইন মুছে ফেলার কী? বা চার, বা পাঁচ?) নিম্নলিখিত এক্সটেনসিবল সমাধান সরবরাহ করেছে:

sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp

তিনটি রেখার অপসারণ প্রসারিত:

sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp

অথবা লাইনগুলির কোয়াড অপসারণ করতে:

sed -e ':top' -e '$!{/\n.*\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1\n\1$/d;P;D' temp

sed সর্বাধিক অন্যান্য বিকল্পগুলির তুলনায় অতিরিক্ত সুবিধা রয়েছে, যা প্রকৃতপক্ষে কোনও স্ট্রিমে পরিচালনা করার ক্ষমতা এবং ডুপ্লিকেটগুলি পরীক্ষা করার জন্য প্রকৃত সংখ্যার লাইনের চেয়ে বেশি মেমরি স্টোরেজ নেই।


কুওনলম মন্তব্যে যেমন উল্লেখ করেছেন , মাল্টি-বাইট অক্ষরযুক্ত লাইনগুলি যথাযথভাবে অপসারণ করতে ব্যর্থতা এড়াতে সিতে লোকাল সেট করা প্রয়োজনীয়। সুতরাং উপরের কমান্ডগুলি হয়ে যায়:

LC_ALL=C sed '$!N;/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
# Etc.

2
@ উইল্ডকার্ড: আপনি লোকেল সেট করতে চাইতে পারেন C, অন্যথায় মাল্টি-বাইট লোকালে, সেই লোকালে অবৈধ অক্ষর কমান্ড ব্যর্থ হওয়ার কারণ হতে পারে।
cuonglm

4

এটি খুব মার্জিত নয়, তবে এটি যতটা সহজ আমি সামনে আসতে পারি:

uniq -c input | awk '{if ($1 % 2 == 1) { print substr($0, 9) }}'

সাবস্ট্রাস্ট () কেবল uniqআউটপুট থেকে ছাঁটাই করে । আপনার কোনও রেখার 9,999,999 টির বেশি নকল না হওয়া পর্যন্ত এটি কাজ করবে (এক্ষেত্রে ইউনিকের আউটপুটটি 9 টিরও বেশি অক্ষর ছড়িয়ে দিতে পারে)।


আমি চেষ্টা করেছিলাম uniq -c input | awk '{if ($1 %2 == 1) { print $2 } }'এবং মনে হয়েছে এটি সমানভাবে ভাল কাজ করবে। substrসংস্করণ আরও ভাল কোন কারণ ?
জোসেফ আর।

1
@ জোসেফআর।, লাইনগুলিতে যদি কোনও সাদা জায়গা থাকে তবে আপনার মন্তব্যের সংস্করণটি ব্যর্থ হবে।
ওয়াইল্ডকার্ড 21

ঐটা সত্য. সেক্ষেত্রে, ক্ষেত্র মুদ্রণ করতে হবে একটি লুপ করার $2জন্য $NFআরো জোরালো হবে?
জোসেফ আর।

@ জোসেফআর: আপনি কেন বিশ্বাস করেন যে আপনার বিকল্পটি আরও শক্তিশালী হবে? একাধিক পরপর জায়গা থাকা অবস্থায় এটি সঠিকভাবে কাজ করতে আপনার অসুবিধা হতে পারে; যেমন foo   bar,।
জি-ম্যান 23

@ জোসেফআর।, না, কারণ এটি সাদা স্থানের সীমানা পরিবর্তন / সরিয়ে দেবে। uniq(কমপক্ষে জিএনইউ কোর্টিলগুলিতে) পাঠ্যের আগেই নির্ভরযোগ্যভাবে 9 টি অক্ষর ব্যবহার করা হয়েছে বলে মনে হয়; যদিও এই নথিটি আমি কোথাও খুঁজে পাচ্ছি না, এবং এটি পসিক্স চশমাগুলিতে নেই
ওয়াইল্ডকার্ড

4

awkনীচে এই স্ক্রিপ্ট চেষ্টা করে দেখুন:

#!/usr/bin/awk -f
{
  if ((NR!=1) && (previous!=$0) && (count%2==1)) {
    print previous;
    count=0;
  }
  previous=$0;
  count++;
}
END {
  if (count%2==1) {
    print previous;
  }
}

ধারণা করা হয় যে lines.txtফাইলটি বাছাই করা হয়েছে।

পরীক্ষা:

$ chmod +x script.awk
$ ./script.awk lines.txt
a
d
e

4

pcregrepএকটি প্রদত্ত নমুনা জন্য সহ :

pcregrep -Mv '(.)\n\1$' file

বা আরও সাধারণ উপায়ে:

pcregrep -Mv '(^.*)\n\1$' file

শেষে "লাইনের শেষ" অ্যাঙ্কর থাকা উচিত নয়? অন্যথায় আপনি এমন একটি লাইনে ব্যর্থ হবেন যা পূর্বের রেখার সাথে মিলবে তার আগে চলমান অক্ষর না রেখে।
ওয়াইল্ডকার্ড

@ উইল্ডকার্ড হ্যাঁ, এটি আরও ভাল। সংশোধন, thx।
jimmij

খুব ঠান্ডা! (+1)
জাজাও

4

যদি ইনপুটটি বাছাই করা হয়:

perl -0pe  'while(s/^(.*)\n\1\n//m){}'

আপনার এখানে অ্যাঙ্করিং ব্যর্থতা রয়েছে। এটি চালানোর চেষ্টা করুন উদাহরণস্বরূপ pineapple\napple\ncoconutএবং আউটপুটটি pinecoconut
ওয়াইল্ডকার্ড

@ উইল্ডকার্ড: আপনাকে ধন্যবাদ তুমি ঠিক. আমার আপডেটটি বুদ্ধিমান হয়েছে কিনা তা দেখুন ...
জেওআও

1
হাঁ। আমি ভাবছিলাম আপনি কেন মডিফায়ার দেওয়ার \nপরিবর্তে ব্যবহার করছেন , তবে আমি বুঝতে পেরেছিলাম যে ব্যবহারগুলি মুছে ফেলা লাইনের পরিবর্তে একটি ফাঁকা রেখা ছেড়ে দেবে। দেখতে এখন ভাল লাগছে; আমি ভুল সংস্করণটি সরিয়েছি যেহেতু এটি কেবল শব্দ যোগ করেছে। :)$/m$
ওয়াইল্ডকার্ড

@ উইল্ডকার্ড, গোলমাল হ্রাস করার জন্য আপনাকে ধন্যবাদ ☺
জেওআও

3

আমি এটির pythonজন্য উদাহরণস্বরূপ, python2.7+ সহ পছন্দ করি

from itertools import groupby
with open('input') as f:
    for k, g in groupby(f):
            if len(list(g)) % 2:
                    print(k),

2

আমি যে প্রশ্নটি বুঝতে পেরেছিলাম, আমি প্রতিটি রেকর্ডের একটি হ্যাশ ব্যবহার করে জোর করে বেছে নিয়েছি, এই ক্ষেত্রে আমি ধরে নিচ্ছি যে আরএস = \ n, তবে অন্য যে কোনও ব্যবস্থা বিবেচনা করার জন্য এটি পরিবর্তন করা যেতে পারে, এটি বিবেচনা করার ব্যবস্থা করা যেতে পারে এমনকি প্যারামিটার বা একটি ছোট সংলাপের সাথে বিজোড়ের পরিবর্তে কয়েকটি সংখ্যক reps। প্রতিটি লাইন হ্যাশ হিসাবে ব্যবহৃত হয় এবং এর গণনা বৃদ্ধি করা হয়, ফাইলের শেষে অ্যারেটি স্ক্যান করা হয় এবং রেকর্ডের প্রতিটি গণনা প্রিন্ট করে। আমি চেক করার জন্য গণনাটি অন্তর্ভুক্ত করছি তবে, এই সমস্যাটি সমাধান করার জন্য একটি [x] অপসারণই যথেষ্ট।

আছে HTH

কাউন্টলাইন কোড

#!/usr/bin/nawk -f
{a[$0]++}
END{for (x in a) if (a[x]%2!=0) print x,a[x] }

নমুনা তথ্য:

a
One Sunny Day
a
a
b
my best friend
my best friend
b
c
c
c
One Sunny Day
c
d
my best friend
my best friend
d
d
d
One Sunny Day
d
e
x
k
j
my best friend
my best friend

নমুনা রান:

countlines feed.txt
j 1
k 1
x 1
a 3
One Sunny Day 3
d 5
e 1

এটি awkকোডের একটি দুর্দান্ত অংশ , তবে দুর্ভাগ্যক্রমে awkসংঘবদ্ধ অ্যারেগুলিকে মোটেই অর্ডার দেওয়া হয় না বা তারা অর্ডার-সংরক্ষণও করে না।
ওয়াইল্ডকার্ড

@ উইল্ডকার্ড, আমি আপনার সাথে একমত, যদি আপনি কোনও সাজানোর আদেশের পরিবর্তে ইনপুট অর্ডারটির প্রয়োজন হয় তবে এটি একটি অতিরিক্ত হ্যাশ কী দ্বারা প্রয়োগ করা যেতে পারে, এর সুবিধাটি হ'ল সাজানোর ক্রম থেকে আপনাকে ইনপুটটি বাছাই করতে হবে না একটি ছোট আউটপুট দিয়ে শেষে তৈরি করা যেতে পারে;)
ময়েসেস নাজার

@ উইল্ডকার্ড যদি আপনার সংরক্ষণের আদেশের প্রয়োজন হয় তবে দয়া করে প্রশ্নে এটি উল্লেখ করুন। এই পদ্ধতিরটিও আমার প্রথম চিন্তা ছিল এবং আপনি ফাইলটি বাছাই করা ধরে নিতে পারি তা ছাড়া আর কোনও অর্ডার উল্লেখ করেন না। অবশ্যই, ফাইলটি বাছাই করা থাকলে আপনি সর্বদা এই সমাধানটির আউটপুটটি পাস করতে পারেন sort
টেরডন

@ ইটারডন, অবশ্যই আপনি সঠিক; আউটপুট ঠিক আবার বাছাই করা যেতে পারে। ভাল যুক্তি. এটিও লক্ষণীয় যে, !=0কীভাবে awkসংখ্যাকে সত্য / মিথ্যা মানগুলিতে রূপান্তর করে এর দ্বারা বোঝানো হয়awk '{a[$0]++}END{for(x in a)if(a[x]%2)print x}'
ওয়াইল্ডকার্ড

1

যদি ইনপুটটি এর অনুসারে বাছাই হয় awk:

awk '{ x[$0]++; if (prev != $0 && x[prev] % 2 == 1) { print prev; } prev = $0; } END { if (x[prev] % 2 == 1) print prev; }' sorted

1

পার্ল সহ:

uniq -c file | perl -lne 'if (m(^\s*(\d+) (.*)$)) {print $2 if $1 % 2 == 1}'

1

শেল কনস্ট্রাক্টস ব্যবহার করে,

uniq -c file | while read a b; do if (( $a & 1 == 1 )); then echo $b; fi done

1
হোয়াইটস্পেসের সাথে শুরু হওয়া বা শেষ হওয়া লাইনের সাথে এটি ভেঙে যায় (বা আরও, কারণ আপনি উদ্ধৃতিটি ভুলে গিয়েছিলেন $b)।
গিলস 'অশুভ হওয়া বন্ধ করুন'

1

মজাদার ধাঁধা!

পার্লে:

#! /usr/bin/env perl

use strict;
use warnings;

my $prev;
while (<>) {
  $prev = $_, next unless defined $prev;  # prime the pump

  if ($prev ne $_) {
    print $prev;
    $prev = $_;                           # first half of a new pair
  }
  else {
    undef $prev;                          # discard and unprime the pump
  }
}

print $prev if defined $prev;             # possible trailing odd line

হাস্কেলের মধ্যে ভার্জুয়েলি:

main :: IO ()
main = interact removePairs
  where removePairs = unlines . go . lines
        go [] = []
        go [a] = [a]
        go (a:b:rest)
          | a == b = go rest
          | otherwise = a : go (b:rest)

হাস্কেল মধ্যে নিখরচায়:

import Data.List (group)
main = interact $ unlines . map head . filter (odd . length) . group . lines

0

একটি সংস্করণ: আমি অভ্যন্তরীণ লুপটি সরল করতে "ডিলিমিটারগুলি" ব্যবহার করি (এটি অনুমান করে যে প্রথম লাইনটি নয় __unlikely_beginning__এবং এটি ধরেছে যে পাঠ্যটি লাইনের সাথে __unlikely_ending__শেষ হচ্ছে না:, এবং ইনপুটড লাইনের শেষে সেই বিশেষ সীমানা লাইন যুক্ত করুন Thus সুতরাং অ্যালগরিদম উভয় ধরে নিতে পারে:)

{ cat INPUTFILE_or_just_-  ; echo "__unlikely_ending__" ; } | awk '
  BEGIN {mem="__unlikely_beginning__"; occured=0; }  

    ($0 == mem)            { occured++ ; next } 

    ( occured%2 )           { print mem ;} 
                            { mem=$0; occured=1; }
'

সুতরাং:

  • আমরা বর্তমানে যে প্যাটার্নটি দেখছি তা আমাদের মনে আছে এবং এটি পুনরুদ্ধার করার সময় একে একে বাড়িয়ে তোলে। [এবং যদি এটি পুনরায় হয় তবে আমরা পরবর্তী 2 টি পদক্ষেপ এড়িয়ে যাচ্ছি, যা প্যাটার্নটি পরিবর্তিত হলে ক্ষেত্রে হয়]
  • যখন প্যাটার্নটি পরিবর্তন হয়:
    • যদি 2 এর একাধিক না হয়, আমরা মুখস্থ প্যাটার্নের একটি ঘটনা মুদ্রণ করি
    • এবং প্রতিটি ক্ষেত্রে যখন প্যাটার্নটি পরিবর্তিত হয়েছে: নতুন মুখস্থ প্যাটার্নটি হ'ল বর্তমান প্যাটার্ন এবং আমরা কেবল এটি একবার দেখেছি।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.