Có phải Go có nếu x trong cấu trúc tương tự như Python không?


289

Không lặp lại trên toàn bộ mảng, làm cách nào để kiểm tra xem xtrong mảng có sử dụng Go không? Liệu ngôn ngữ có một cấu trúc?

Giống như Python: if "x" in array: ...


2
Có thể là bản sao của stackoverflow.com/q/8307478/180100

7
AFAIK, không có tốc ký cho điều đó đi. Trong nội bộ, python cũng lặp đi lặp lại trên mảng, không có xung quanh đó.
Tiếng Đan Mạch94

6
BTW, một lưu ý quan trọng cho vấn đề này là không có cách nào để làm điều này (như bạn yêu cầu) " [w] ithout lặp đi lặp lại trên toàn bộ mảng". Làm cho các vòng lặp như vậy rõ ràng (hoặc đằng sau một chức năng như strings.Index) giúp làm rõ hơn những gì mã đang làm. Tôi có ấn tượng rằng có lẽ bạn nghĩ Python in array:đang làm gì đó nhanh / ma thuật. AFAIK thì không. Làm cho vòng lặp rõ ràng giúp làm cho người viết (và tất cả người đọc) nhận thức và xem xét các triển khai khác (ví dụ: bản đồ).
Dave C

5
Tuy nhiên, nếu "x" trong bộ thực sự rất nhanh.
Roberto Alsina

6
Tôi không nghĩ rằng chúng tôi đang yêu cầu một cách tiếp cận nhanh chóng theo chương trình, chúng tôi chỉ yêu cầu một cách ngắn gọn (và vẫn chưa có ...)
Migwell

Câu trả lời:


340

Không có toán tử tích hợp để thực hiện trong Go. Bạn cần lặp lại trên mảng. Bạn có thể viết chức năng của riêng bạn để làm điều đó, như thế này:

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

Nếu bạn muốn có thể kiểm tra tư cách thành viên mà không lặp lại toàn bộ danh sách, bạn cần sử dụng bản đồ thay vì một mảng hoặc lát, như thế này:

visitedURL := map[string]bool {
    "http://www.google.com": true,
    "https://paypal.com": true,
}
if visitedURL[thisSite] {
    fmt.Println("Already been here.")
}

4
Có cách nào để làm điều này mà không chỉ định loại? giả sử nếu tôi chỉ muốn một hàm kimInHaystack chung (kim, haystack) mà không có các phương thức riêng biệt cho từng loại
Allen

25
Nó có thể được thực hiện với gói phản chiếu, nhưng nó sẽ khá kém hiệu quả (có thể chậm như thể bạn đã viết nó ra bằng một ngôn ngữ động như Python). Ngoài ra, không. Đó là những gì mọi người muốn nói khi họ nói rằng Go không có thuốc generic.
andybalholm

2
Bất cứ ai vấp phải câu trả lời này đều phải lưu ý rằng bạn KHÔNG THỂ sắp xếp bản đồ. Nhược điểm lớn để sử dụng bản đồ đi.
RisingSun

4
bạn cũng không thể sắp xếp bản đồ (đối tượng) trong Javascript. Đó là một lỗi v8 mà các đối tượng trả về các giá trị theo thứ tự bảng chữ cái.
kumarharsh 24/2/2016

7
bản đồ không được sắp xếp theo hầu hết các ngôn ngữ - đó là mệnh cho khóa học về cấu trúc dữ liệu bản đồ (hashmap).
Hejazzman

100

Một giải pháp khác nếu danh sách chứa các giá trị tĩnh.

ví dụ: kiểm tra giá trị hợp lệ từ danh sách các giá trị hợp lệ:

func IsValidCategory(category string) bool {
    switch category {
    case
        "auto",
        "news",
        "sport",
        "music":
        return true
    }
    return false
}

11
Vâng, nếu "giá trị hợp lệ" của bạn đến từ cơ sở dữ liệu thì sao?
Rami Dabain

Vâng, điều này là gọn gàng nhưng chỉ khi các giá trị này có thể được xác định trước.
piggybox

2
@RonanDejhero sau đó tôi có thể sử dụng WHERE: myValue IN (truy vấn phụ) :)
anilech

3
Đây là gọn gàng so với câu trả lời hàng đầu
piggybox

50

Đây là trích dẫn từ cuốn sách "Lập trình trong Go: Tạo ứng dụng cho thế kỷ 21":

Sử dụng một tìm kiếm tuyến tính đơn giản như thế này là tùy chọn duy nhất cho dữ liệu chưa được sắp xếp và tốt cho các lát nhỏ (tối đa hàng trăm mục). Nhưng đối với các lát cắt lớn hơn, đặc biệt là nếu chúng tôi thực hiện tìm kiếm nhiều lần, thì tìm kiếm tuyến tính rất kém hiệu quả, trung bình cần một nửa các mục để so sánh mỗi lần.

Go cung cấp phương thức sort.Search () sử dụng thuật toán tìm kiếm nhị phân: Điều này yêu cầu so sánh chỉ các mục log2 (n) (trong đó n là số lượng mục) mỗi lần. Để đặt điều này trong viễn cảnh, một tìm kiếm tuyến tính của 1000000 mục yêu cầu trung bình 500000 so sánh, trong trường hợp xấu nhất là 1000000 so sánh; một tìm kiếm nhị phân cần tối đa 20 so sánh, ngay cả trong trường hợp xấu nhất.

files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.Search(len(files),
    func(i int) bool { return files[i] >= target })
if i < len(files) && files[i] == target {
    fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}

https://play.golang.org/p/UIndYQ8FeW


10
Điều này chỉ có ý nghĩa nếu bạn thực hiện tìm kiếm lặp đi lặp lại. Mặt khác, bạn có độ phức tạp n * log (n) * log (n) cho tìm kiếm sắp xếp và nhị phân, so với chỉ n cho tìm kiếm tuyến tính.
christian

1
Đó thực sự chỉ là n*log(n) + log(n), vì đó là hai hoạt động độc lập có kết quả
pomo_mondreganto

27

Ví dụ trên sử dụng sort rất gần, nhưng trong trường hợp chuỗi chỉ cần sử dụng SearchString:

files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.SearchStrings(files, target)
if i < len(files) && files[i] == target {
    fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}

https://golang.org/pkg/sort/#SearchStrings


2
Câu trả lời này trông giống như một bản sao dán ít thông tin hơn của câu trả lời dưới đây, đã xảy ra trước câu trả lời này.
cytinus

@cytinus Câu trả lời nào bạn đang đề cập đến? Đó là người duy nhất tôi thấy dựa trên sort.SearchStrings.
akim

1
Tôi đã tăng tốc 100 lần cho các tìm kiếm lặp đi lặp lại qua một lát lớn.
Xeoncross

20

Chỉ cần có câu hỏi tương tự và quyết định thử một số gợi ý trong chủ đề này.

Tôi đã điểm chuẩn các tình huống tốt nhất và tồi tệ nhất trong 3 loại tra cứu:

  • sử dụng bản đồ
  • sử dụng một danh sách
  • sử dụng câu lệnh chuyển đổi

đây là mã chức năng:

func belongsToMap(lookup string) bool {
list := map[string]bool{
    "900898296857": true,
    "900898302052": true,
    "900898296492": true,
    "900898296850": true,
    "900898296703": true,
    "900898296633": true,
    "900898296613": true,
    "900898296615": true,
    "900898296620": true,
    "900898296636": true,
}
if _, ok := list[lookup]; ok {
    return true
} else {
    return false
}
}


func belongsToList(lookup string) bool {
list := []string{
    "900898296857",
    "900898302052",
    "900898296492",
    "900898296850",
    "900898296703",
    "900898296633",
    "900898296613",
    "900898296615",
    "900898296620",
    "900898296636",
}
for _, val := range list {
    if val == lookup {
        return true
    }
}
return false
}

func belongsToSwitch(lookup string) bool {
switch lookup {
case
    "900898296857",
    "900898302052",
    "900898296492",
    "900898296850",
    "900898296703",
    "900898296633",
    "900898296613",
    "900898296615",
    "900898296620",
    "900898296636":
    return true
}
return false
}

trường hợp tốt nhất chọn mục đầu tiên trong danh sách, trường hợp xấu nhất sử dụng giá trị không tồn tại.

đây là kết quả:

BenchmarkBelongsToMapWorstCase-4 2000000 787 ns/op BenchmarkBelongsToSwitchWorstCase-4 2000000000 0.35 ns/op BenchmarkBelongsToListWorstCase-4 100000000 14.7 ns/op BenchmarkBelongsToMapBestCase-4 2000000 683 ns/op BenchmarkBelongsToSwitchBestCase-4 100000000 10.6 ns/op BenchmarkBelongsToListBestCase-4 100000000 10.4 ns/op

Switch thắng tất cả các cách, trường hợp xấu nhất là nhanh hơn so với trường hợp tốt nhất. Bản đồ là tồi tệ nhất và danh sách gần hơn để chuyển đổi.

Vì vậy, đạo đức là: Nếu bạn có một danh sách nhỏ, hợp lý, câu lệnh chuyển đổi là cách để đi.


Tôi không biết nếu Go tối ưu hóa trường hợp này, nhưng nó có tạo ra sự khác biệt nếu bạn di chuyển việc khởi tạo danh sách / bản đồ bên ngoài chức năng kiểm tra không?
w00t

Tôi tò mò muốn xem so sánh sẽ diễn ra như thế nào với một danh sách được sắp xếp và liệu loại đó có xứng đáng hay không
Michael Draper

Những gì về :thay vì ,trong câu lệnh switch? Nó làm cho nó nhanh hơn?
Thomas Sauvajon

Tôi đã thử sử dụng nhiều casecâu lệnh thay vì một trường hợp duy nhất. Kết quả là hợp lý giống nhau với cả hai chức năng.
Thomas Sauvajon

7

Một tùy chọn khác là sử dụng bản đồ như một bộ. Bạn chỉ sử dụng các khóa và có giá trị giống như một boolean luôn luôn đúng. Sau đó, bạn có thể dễ dàng kiểm tra xem bản đồ có chứa chìa khóa hay không. Điều này hữu ích nếu bạn cần hành vi của một tập hợp, trong đó nếu bạn thêm một giá trị nhiều lần thì nó chỉ trong tập hợp một lần.

Đây là một ví dụ đơn giản trong đó tôi thêm các số ngẫu nhiên làm khóa vào bản đồ. Nếu cùng một số được tạo ra nhiều lần, điều đó không thành vấn đề, nó sẽ chỉ xuất hiện trong bản đồ cuối cùng một lần. Sau đó, tôi sử dụng một đơn giản nếu kiểm tra để xem liệu một phím có trong bản đồ hay không.

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    var MAX int = 10

    m := make(map[int]bool)

    for i := 0; i <= MAX; i++ {
        m[rand.Intn(MAX)] = true
    }

    for i := 0; i <= MAX; i++ {
        if _, ok := m[i]; ok {
            fmt.Printf("%v is in map\n", i)
        } else {
            fmt.Printf("%v is not in map\n", i)
        }
    }
}

Đây là trên sân chơi đi


0

Điều này gần đến mức tôi có thể có được cảm giác tự nhiên của toán tử "in" của Python. Bạn phải xác định loại của riêng bạn. Sau đó, bạn có thể mở rộng chức năng của loại đó bằng cách thêm một phương thức như "có" hoạt động như bạn hy vọng.

package main

import "fmt"

type StrSlice []string

func (list StrSlice) Has(a string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func main() {
    var testList = StrSlice{"The", "big", "dog", "has", "fleas"}

    if testList.Has("dog") {
        fmt.Println("Yay!")
    }
}

Tôi có một thư viện tiện ích nơi tôi xác định một vài thứ phổ biến như thế này cho một số loại lát, như những loại có chứa số nguyên hoặc các cấu trúc khác của riêng tôi.

Vâng, nó chạy trong thời gian tuyến tính, nhưng đó không phải là vấn đề. Vấn đề là hỏi và tìm hiểu những cấu trúc ngôn ngữ phổ biến mà Go có và không có. Đó là một bài tập tốt. Cho dù câu trả lời này là ngớ ngẩn hay hữu ích là tùy thuộc vào người đọc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.