2012-02-12 2 views
28

값이 있는지 슬라이스/맵을 검사하는 방법이 있습니까?이동 : 고유 한 경우 추가

나는 그것이 않는 경우 하지이 슬라이스에 존재 슬라이스 에 값을 추가하고 싶습니다.

이 방법은 효과가 있지만 자세한 정보입니다. 이것을하기에 더 좋은 방법이 있습니까?

orgSlice := []int{1, 2, 3} 
newSlice := []int{} 
newInt := 2 

newSlice = append(newSlice, newInt) 
for _, v := range orgSlice { 
    if v != newInt { 
     newSlice = append(newSlice, v) 
    } 
} 

newSlice == [2 1 3] 
+1

Re : EDIT - 모든 유효한지도 키 유형에 대해 동일한 이야기입니다. 문자열이 있습니다. – zzzz

+1

Re : EDIT2 - 'newSlice'의 값 순서가 중요하지 않고 범위 문을 사용하여 사용/사용하게되면 구성이 중복됩니다. 'set'의 키 범위 만 지정하십시오. – zzzz

+0

@jnml 의견을 보내 주셔서 감사합니다. 나는'ints'의 목록을 GAE 데이터 저장소에 저장하고 있습니다. 질의를하기 위해서는 슬라이스 ('[] int') 여야합니다. 그 요구 사항은 나의 초기 기술을 더 나은 선택으로 만들어 주는가? 목록은 작을 것이다. –

답변

46

각 삽입마다 선형적인 시간이 걸립니다. 더 좋은 방법은 map[int]struct{}을 사용하는 것입니다. 또는 map[int]bool 또는 이와 유사한 것을 사용할 수도 있지만 비어있는 struct{}은 추가 공간을 차지하지 않는다는 이점이 있습니다. 따라서 map[int]struct{}은 정수 집합에 대한 인기있는 선택입니다.

예 :

set := make(map[int]struct{}) 
set[1] = struct{}{} 
set[2] = struct{}{} 
set[1] = struct{}{} 
// ... 

for key := range(set) { 
    fmt.Println(key) 
} 
// each value will be printed only once, in no particular order 


// you can use the ,ok idiom to check for existing keys 
if _, ok := set[1]; ok { 
    fmt.Println("element found") 
} else { 
    fmt.Println("element not found") 
} 
+0

답장을 보내 주셔서 감사합니다. 몇 가지 질문 : 슬라이스를 어떻게 다시 만들었습니까? 이 전략을 문자열로 사용할 수있는 방법이 있습니까? 미안하지만 분명하다면 - 나는 새로 온다. –

+3

O (n) 대신 O (1) 동작이 있기 때문에 계산 중에 그냥 맵을 사용합니다. 그런 다음 슬라이스를 만들고 맵에서 각 값을 복사 할 수 있습니다. 그 이후에는 요소가 임의의 순서로 정렬되므로 정렬 할 수 있습니다.그리고 int, float, struct, string 및 배열을지도 키 (적어도 Go1에서는)로 사용할 수 있습니다. – tux21b

+0

빈 구조체가 추가 공간을 차지하지 않는다는 점을 구체적으로 설명해 주셔서 감사합니다. 나는 이것을 몰랐고 map [type] interface {}를 사용할 것이고 인터페이스에 nil을 할당 할 것이다. – user1943442

22

가장 효율적인 가능성은 슬라이스 반복하고 당신이 그것을 찾을 수없는 경우 추가합니다.

func AppendIfMissing(slice []int, i int) []int { 
    for _, ele := range slice { 
     if ele == i { 
      return slice 
     } 
    } 
    return append(slice, i) 
} 

작은 목록의 경우 빠르고 간단합니다.

또한 현재지도 기반 솔루션보다 항상 빠릅니다. 지도 기반 솔루션은 무엇을 상관없이 전체 슬라이스를 반복합니다. 이 솔루션은 새로운 값이 이미 있음을 발견하면 즉시 반환합니다. 두 솔루션 모두 반복되는 요소를 비교합니다. (각 맵 지정 문은 적어도 내부적으로 하나 이상의 맵 키 비교를 수행합니다.) 맵은 많은 삽입에서 유지할 수있는 경우에만 유용합니다. 삽입 할 때마다 다시 작성하면 모든 이점이 손실됩니다.

큰 목록을 효율적으로 처리해야하는 경우 목록을 정렬 된 순서로 유지하는 것이 좋습니다. 목록의 처음에 추가 된 첫 번째 솔루션과 마지막 솔루션이 끝에 추가되므로 순서가 중요하지 않은 것으로 판단됩니다. 목록을 항상 정렬 된 상태로 유지하면 sort.Search 함수를 사용하여 효율적인 바이너리 삽입을 수행합니다.

+8

"맵 기반 솔루션은 무엇을 막론하고 전체 슬라이스를 반복합니다."- 이것이 해시 맵의 작동 방식이라고 확신합니까? – Ottokar

+0

@Ottokar, 그가 틀렸어? 많은 사람들이 upvoted하지만 응답이 남아 있지 않습니다. –

+1

@FilipBartuzi 사실, 나는 그 진술의 의미를 오해했을 수도 있습니다. 해시 맵은 분명히 키를 찾기 위해 요소를 반복하지 않지만, "맵 기반 솔루션"은 "고유 한 경우 슬라이스 추가"는 슬라이스를 맵으로 변환 한 다음 맵을 슬라이스로 다시 변환해야하는 경우 이점을 상실합니다 . – Ottokar

관련 문제