이론

이론

두 개의 열이 있는 공백 또는 쉼표로 구분된 테이블이 있고 각 행은 두 단어의 동등성을 나타냅니다.

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:동일한 값을 두 번 추가하는 것을 건너뜁니다. 이것이 필요한지 또는 소스에 그러한 예외가 있는지 확실하지 않습니다. 테스트를 생략하고 항상 실행할 수 있습니다 l.append(y).

코드는 먼저 공백으로 분할을 시도한 다음 쉼표를 다시 시도합니다. 이는 쉼표로 구분된 줄에 공백이 없다고 가정합니다(즉 공백이 아님 A, B).

중첩 for루프는 (내가 아는 한) 파이썬의 특징을 사용합니다. 즉, break 문이 아니라 else루프가 Exhaustion 을 통해 끝날 때만 실행됩니다 . forx, 찾을 수 없는 경우 해당 쌍이 새 목록으로 추가됩니다 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

이상한 솔루션

어쩌면 이 사이트에 더 적합할 수도 있습니다.

여기서는 서로소 집합의 약간 다른 구현을 사용합니다. 각 하위 집합은 해당 요소 중 하나("리더")로 표시됩니다. 이로 인해 결합 작업이 느려지지만 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

관련 정보