2つの列を持つスペースまたはカンマ区切りのテーブルがあり、各行は2つの単語の同等性を表します。
A B
B C
B D
C E
F G
私が望むのは、互いに等しいすべての単語をリストする各行を持つテーブルです。
A B C D E
F G
つまり、両方の単語が同じ入力行に表示される場合は、最終的に同じ出力行に表示される必要があります。
どんなツールでも可能です。
答え1
Pythonは入力ファイルを引数で始めます。
import sys
res = [] # list of lists
for line in open(sys.argv[1]):
try:
x, y = line.split() # split on space
except ValueError:
line = line.rstrip()
x, y = line.split(',') # retry with comma
for l in res:
if x in l:
if y not in l:
l.append(y)
break
else:
res.append([x, y])
for line in res:
print ' '.join(line)
テストでは、if y not in l:
同じ値を2回追加することをスキップします。これが必要かどうか、ソースにそのような例外があるかどうかはわかりません。テストを省略して常に実行できますl.append(y)
。
コードは最初にスペースに分割し、次にコンマを再試行します。これは、カンマで区切られた行にスペースがないと仮定します(つまりスペースではないA, B
)。
ネストされたfor
ループは(私が知る限り)Pythonの機能を使用します。つまり、breakステートメントではなく、else
ループがExhaustionを介して終了したときにのみ実行されます。for
つまりx
、見つからない場合は、そのペアが新しいリストとして追加されますres
。
答え2
理論
この問題はコレクションを分ける入力する同等クラス、入力ファイルにはペアごとの同等性がリストされます。この問題は、次のツールを使用して解決できます。お互いのセットデータ構造
あまり抽象的でない例は、例えば、同義語のペアが与えられた同義語のグループに単語を分割することである。
large big
big great
great vast
small little
little tiny
になる:
large big great vast
small little tiny
ルビー溶液
互いのセットはRuby標準ライブラリでは使用できないため、Rubyを使用してこれをエミュレートしましたHash
(他の場所では「連想配列」、「辞書」、「マップ」とも呼ばれます)。
#!/usr/bin/env ruby
# new elements end up in "singleton subsets"
subsets = Hash.new { |subsets, element| subsets[element] = [element] }
ARGF.each do |line|
x, y = line.scan(/[^\s,]/)
# these two emulate disjoint-set's "find" operation
x_set = subsets[x]
y_set = subsets[y]
# and this loop implements disjoint-set's "union"
y_set.each do |element, _|
subsets[element] = x_set << element
end unless x_set == y_set
end
puts subsets.values.uniq.map{|set| set.join(" ")}
使用法
これには、コマンドラインにファイル名が必要であるか、標準入力にデータが必要です。
$ ruby so-162730.rb input.txt
A B C D E
F G
$ ruby so-162730.rb < input.txt
A B C D E
F G
奇妙なソリューション
たぶんこのサイトに適しているかもしれません。
ここでは、互いのセットのわずかに異なる実装を使用します。各サブセットは、対応する要素の1つ(「リーダー」)として表示されます。これは結合操作を遅くしますが、awkの単純なデータ型を使用して実装する方が簡単です。
{
union(find($1), find($2));
}
END {
format_subsets();
for(i in subsets)
print subsets[i];
}
function find(element) {
if (!leaders[element])
leaders[element] = element;
return leaders[element];
}
function union(leader_1, leader_2) {
for(i in leaders)
if (leaders[i] == leader_2)
leaders[i] = leader_1;
}
function format_subsets() {
for(element in leaders) {
leader = leaders[element]
subsets[leader] = (subset = subsets[leader]) ? (subset OFS element) : element;
}
}
使用法
$ awk -f so-162730.awk < input.txt
A B C D E
F G
またはスペースまたはカンマで区切られた入力の場合:
$ awk -f so-162730.awk -F '[[:space:]]+|,' input.txt
A B C D E
F G