Find all matches in Go array
Asked Answered
E

3

6

I have an array of structs (struct detailed at bottom)

I want to find all the structs that match certain values for, example, leg and site.

So if leg=101 and site=1024A give back all the structs that match these criteria.

What is the Go manner for doing this?

type JanusDepth struct {
    dataset string
    ob      string
    leg     string  
    site    string  
    hole    string
    age     float64
    depth   float64
    long    float64
    lat     float64
}
Endotoxin answered 11/10, 2013 at 16:17 Comment(1)
You'll have to loop and test. That's all.Closehauled
B
10

Dead simple:

leg      := "101"
site     := "1024A"
filtered := []JanusDepth{}

for _, e := range MyArrayOfStructs {
    if(e.leg == leg && e.site == site) {
        filtered = append(filtered, e)
    }
}

// filtered contains your elements
Barry answered 11/10, 2013 at 16:25 Comment(3)
Is that the idiomatic go way to do it? I didn't know if there was something like a find or findall type approach ala Groovy etc. I guess I didn't think iterating through every array element would be the solution.Endotoxin
Yes, that is idiomatic. While it is possible to do a Find function that makes use of reflection to do what you are after, iteration over the slice is trivial and much more efficient. That is probably the reason why they haven't implemented any Find function in the standard libraries.Gardenia
ANisus Thanks for the info... I guess I should have expected Go to be more C like that Java like. :) I just thought a full on iterating wouldn't be the best approach. I'll mark tomwilde's answer accepted. Given the size of my data though, I think I need to come up with some way to marshal things better a priori .... otherwise I am going to be spending a lot of time in loops.Endotoxin
O
2

If your data is ordered on one key, then you can use http://golang.org/pkg/sort/#Search to do a binary search, which is better for performance if the amount of data is moderate to large.

Oatcake answered 13/10, 2013 at 1:20 Comment(0)
D
0

More than 10 years later, I'm wondering why I can't find anything better than a manual for loop in order to filter some data from a list. I've came to create custom helper functions for this, as follows:

// Filter the slice based on the predicate and return the result
func filter[S ~[]T, T any](slice S, predicate func(T) bool) []T {
    out := make([]T, 0)

    for _, item := range slice {
        if predicate(item) {
            out = append(out, item)
        }
    }

    return out
}

// For cases where you have to filter the slice and also keep the items that do not match the predicate
func filterOr[S ~[]T, T any](slice S, predicate func(T) bool) ([]T, []T) {
    out := make([]T, 0)
    orOut := make([]T, 0)

    for _, item := range slice {
        if predicate(item) {
            out = append(out, item)
        } else {
            orOut = append(orOut, item)
        }
    }

    return out, orOut
}

They can then be used like this:

package main

import "fmt"

func isEven(num int) bool { return num%2 == 0 }

func main() {
    initialSlice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    evenNumbers1 := filter(initialSlice, isEven)

    // Even numbers: [2 4 6 8 10]
    fmt.Printf("Even numbers: %v\n", evenNumbers1)

    evenNumbers2, oddNumbers := filterOr(initialSlice, isEven)

    // Even numbers: [2 4 6 8 10]
    fmt.Printf("Even numbers: %v\n", evenNumbers2)
    // Odd numbers: [1 3 5 7 9]     
    fmt.Printf("Odd numbers: %v\n", oddNumbers)
}

Thanks to this, my code is a little less bloated.

Display answered 20/8 at 15:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.