単語のリストがたくさんあります。単語の多くは、末尾にsが付いているため、異なるだけです。リスト上の単語がリスト上の別の単語とまったく同じである場合、単語の1つが文字sで終わることを除いて、sで終わる重複する単語を削除したいと思います。また、単語の現在の位置を維持できるように、リストを並べ替えることなくこれを実現したいと思います。
入力例:
frog
dogs
cats
cat
dog
frogs
catfish
octopus
出力例:
frog
cat
dog
catfish
octopus
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
これはいくつかの方法で行うことができます。たとえば、最も簡単な方法は、データを並べ替えて隣接する行を比較することです。
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
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
リストはstdinから読み取られます。テスト実行は次のとおりです。
$ cat file1
frog
dogs
cats
cat
dog
frogs
catfish
$ ./remove-s.sh < file1
frog
cat
dog
catfish
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
#! /usr/bin/Perl
use strict;
my %words = ();
my $index = 1; # keep track of the order that words were read in
while (<>) {
chomp;
$words{$_} = $index++
}
# sort %words hash by value to print words in the same order
# that they were seen.
foreach (sort { $words{$a} <=> $words{$b} } keys %words) {
my $Word = $_;
$Word =~ s/s$//;
next if ( ($Word ne $_) && (defined $words{$Word}) );
print "$_\n";
}
出力:
frog
cat
dog
catfish
octopus
これは、awk
を使用した単純化されたソリューションであり、語順は保持されません。
{
len = length($1);
prefix = $1;
if (substr($1, len) == "s") {
prefix = substr($1, 1, len - 1);
}
if (prefix in data) {
next;
} else {
print prefix;
data[prefix] = 1;
}
}
語順を維持することが不可欠な場合は、すべての行をメモリに保持し、ファイル全体が読み取られた後にリストを処理する必要があります。
{
line[FNR] = $0;
len = length($1);
if (substr($1, len) == "s") {
prefix = substr($1, 1, len - 1);
if (prefix in data) {
line[FNR] = "";
next;
} else {
data[prefix] = FNR;
}
} else {
num = data[$1];
if (num) {
line[num] = "";
} else {
data[$1] = FNR;
}
}
}
END {
for (i = 1; i <= FNR; i++) {
if (line[i]) {
print line[i];
}
}
}