Golang에서 데이터 구조 설정


69

나는 Google golang을 정말로 좋아하지만 표준 라이브러리의 세트와 같은 기본 데이터 구조를 생략 한 구현 자에 대한 이론적 근거가 무엇인지 설명 할 수 있습니까?


8
언어는 실제로 이동하지 golang라고
jozefg

92
그러나 "golang"은보다 검색 가능합니다.
Matt

18
더 검색 가능한 방법. 인터넷 검색 "go set"은 흑백 조각이있는 나무 보드의 이미지를 반환합니다.
Doug Richardson

답변:


68

이 생략의 한 가지 잠재적 인 이유는지도를 사용하여 세트를 모델링하기가 쉽기 때문입니다.

솔직히 말해서 그것은 약간의 감독이라고 생각하지만 이야기는 정확히 동일합니다. Perl에는 목록과 해시 테이블이 있고 Go에는 배열, 슬라이스 및 맵이 있습니다. Perl에서는 일반적으로 세트와 관련된 모든 문제에 대해 해시 테이블을 사용하며 Go에도 적용됩니다.

Go에서 설정된 정수를 모방하기 위해 맵을 정의합니다.

set := make(map[int]bool)

무언가를 추가하는 것은 다음과 같이 쉽습니다.

i := valueToAdd()
set[i] = true

무언가를 삭제하는 것은 단지

delete(set, i)

그리고이 구조의 잠재적 인 어색함은 쉽게 추상화됩니다.

type IntSet struct {
    set map[int]bool
}

func (set *IntSet) Add(i int) bool {
    _, found := set.set[i]
    set.set[i] = true
    return !found   //False if it existed already
}

그리고 delete 및 get을 유사하게 정의 할 수 있습니다 . 여기 에는 완전한 구현이 있습니다 . 여기서 가장 큰 단점은 이동에 제네릭이 없다는 사실입니다. 그러나이 interface{}경우 get의 결과를 캐스팅 한 경우이 작업을 수행 할 수 있습니다.


3
다음은 Contains 및 Size 메서드를 사용하여 약간 수정 된 버전입니다. play.golang.org/p/tDdutH672-
Rick-777

19
대신에 대신 map[int]bool사용할 수 있습니다 map[int]struct{}. 나는 마지막을 선호합니다.
pepper_chico

20
map[int]struct{}.. struct{}0 바이트가 걸립니다.
Boopathi Rajaa

2
github.com/fatih/set은지 도와 빈 구조체를 기반으로 한 구현입니다. 스레드 안전하고 간단한 API가 있습니다.
Fatih Arslan

6
map[int]struct{}당신 과 함께 if mymap["key"] {회원을 확인할 수 없습니다 . Google bool ( "세트 구현 가능"검색)을 사용하는 것이 좋습니다 .
Timmmm

3

나는 이것이 golang단순성에 초점을 맞추고 있다고 생각합니다 . set정말 유용하게 s의 difference, intersection, union, issubset, 등 .. 방법. 아마도 golang팀은 하나의 데이터 구조에 비해 너무 많은 것으로 생각했습니다. 하지만, 그 밖에는있는 "바보 세트" add, contains그리고 remove쉽게로 복제 할 수 있습니다 map로 @jozefg에 의해 설명했다.


동의하지 않습니다. 집합은 주로 회원 확인 및 고유성 의미에 사용됩니다. 이러한 구현 없이는 집합 구현을 완벽하게 사용할 수 있습니다. 말하자면, 그들은 또한 구현하기가 쉽지 않습니다.
Sedat Kapanoglu

2

이전 답변은 키가 내장 유형 인 경우에만 작동합니다. 이전 답변을 보완하기 위해 요소가 사용자 정의 유형 인 세트를 구현하는 방법은 다음과 같습니다.

package math

// types

type IntPoint struct {
    X, Y int
}

// set implementation for small number of items
type IntPointSet struct {
    slice []IntPoint 
}

// functions

func (p1 IntPoint) Equals(p2 IntPoint) bool {
    return (p1.X == p2.X) && (p1.Y == p2.Y)
}

func (set *IntPointSet) Add(p IntPoint) {
    if ! set.Contains(p) {
        set.slice = append(set.slice, p)
    }
}

func (set IntPointSet) Contains(p IntPoint) bool {
  for _, v := range set.slice {
    if v.Equals(p) {
      return true
    }
  }
  return false
}

func (set IntPointSet) NumElements() int {
    return len(set.slice)
}

func NewIntPointSet() IntPointSet {
  return IntPointSet{(make([]IntPoint, 0, 10))}
}

8
"키가 내장 유형 인 경우에만 작동합니다"가 잘못되었습니다 . type mySet map[IntPoint]bool완벽하게 작동합니다. 모든 것은이지도에 사용되는 키의 형태를 요구이다 가 가지고 ==!= . 구조체 유형의 평등이 잘 정의되어 Equals있으므로 방법은이어야합니다 p1 == p2.
Dave C

1
구조체에 대한 동등성이 명확하게 정의되어 있지만 구조체에 맵 또는 슬라이스가 필드로 포함되어 있으면 값이 아닌 참조로 비교됩니다. 이것은 당신이 원하는 것이 아닐 수도 있습니다.
Chaim-Leib Halbert

1
멤버 수에 관계없이 일정한 시간이 Contains걸리고 선형 시간이 걸리기 때문에이 솔루션에 약간의 문제가 aMap[]있습니다. 더 나은 솔루션은 내부적으로 각 멤버의 컨텐츠를 기반으로 고유 한 키를 작성하고 map유형이 제공 하는 상수 시간 조회를 활용 합니다. 캐시 동작 등을 고려한 더 빠른 솔루션도 존재합니다.
Chaim-Leib Halbert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.