末尾にSがない重複項目が同じリストにある場合、文字Sで終わる単語をどのように削除しますか?

末尾にSがない重複項目が同じリストにある場合、文字Sで終わる単語をどのように削除しますか?

私は膨大な量の単語のコレクションを持っています。多くの単語は末尾に文字sがあるので異なります。リスト内の単語が文字sで終わる単語の1つを除いて、リスト内の他の単語とまったく同じ場合は、sで終わる重複単語を削除したいと思います。また、単語の現在位置を維持できるようにリストを並べ替える必要なく、これを行いたいと思います。

入力例:

frog
dogs
cats
cat
dog
frogs
catfish
octopus

出力例:

frog
cat
dog
catfish
octopus

答え1

awkを使用してファイルを2回読みます。最後に s がある配列にすべての変数を格納します。 2番目の実行では、各行の配列を確認し、その行が配列にない場合は印刷します。

awk 'FNR==NR{a[$0 "s"]++;next}!($0 in a)' file.txt file.txt

少ないメモリを使用するには、次のこともできます。

awk 'FNR==NR{!/s$/ && a[$0 "s"]++;next}!($0 in a)' file.txt file.txt

答え2

これはさまざまな方法で実行できます。たとえば、最も簡単な方法は、データをソートし、隣接する行を比較することです。

sort foo |awk '{ if ( plural[$1] == "" ) print; plural[$1 "s"] = 1; }'

与えられた入力

frog
dogs
cats
catfish
cat
dog
frogs

出力

cat
catfish
dog
frog

ソートされていません:

#!/bin/sh
awk 'BEGIN { count=0; }
{
        words[count++] = $1;
        plurals[$1 "s"] = $1;
}
END {
        for ( n = 0; n < count; ++n) {
                if ( plurals[words[n]] == "")
                        print words[n];
        }
}
' <foo

出力:

frog
catfish
cat
dog

答え3

Bashスクリプトを使用してください。

#!/bin/bash

readarray -t mylist

# compare each item on the list with a new list created by appending `s'
# to each item of the original list

for i in "${mylist[@]}"; do
  for j in "${mylist[@]/%/s}"; do
    [[ "$i" == "$j" ]] && continue 2
  done
  echo "$i"
done

リストは標準入力から読み取られます。テストの実行は次のとおりです。

$ cat file1
frog
dogs
cats
cat
dog
frogs
catfish
$ ./remove-s.sh < file1 
frog
cat
dog
catfish

答え4

grep -f(ファイルからパターンを取得する)オプションの乱用:

grep 's$' input       | # output: all lines ending with s 
  sed -e 's/s$//'     | # those same entries, minus the s
  grep -F -x -f input | # the entries whose plurals appear
  sed -e 's/$/s/'     | # the plurals to remove
  grep -F -x -v -f - input

関連情報