Created
September 19, 2023 20:54
-
-
Save scottcagno/835bcc93d6ad990086c620eefd69d4a4 to your computer and use it in GitHub Desktop.
Simple beginnings of a search engine type thing...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"io" | |
"log" | |
"os" | |
"regexp" | |
"sort" | |
"strconv" | |
"strings" | |
) | |
func main() { | |
data := [][]string{ | |
{"foo", "bar", "baz"}, | |
{"one", "two", "three", "four"}, | |
{"five", "one", "two", "nine"}, | |
{"three", "eleven", "eighteen"}, | |
} | |
items := OpenSortedItems(data) | |
res := Search("eleven", items) | |
fmt.Println(res, data[3][1]) | |
} | |
type Item interface { | |
Search(pattern string) *Result | |
} | |
type Result struct { | |
Ident string | |
Offsets []int | |
} | |
func Search(pattern string, items []Item) *Result { | |
c := make(chan *Result) | |
search := func(i int) { | |
c <- items[i].Search(pattern) | |
} | |
for i := range items { | |
go search(i) | |
} | |
for { | |
select { | |
case res := <-c: | |
if res == nil { | |
continue | |
} | |
fmt.Printf("Got result: %+v\n", res) | |
return res | |
} | |
} | |
//return <-c | |
} | |
func fanIn[T any](input1, input2 <-chan T) <-chan T { | |
c := make(chan T) | |
go func() { | |
for { | |
select { | |
case v := <-input1: | |
c <- v | |
case v := <-input2: | |
c <- v | |
} | |
} | |
}() | |
return c | |
} | |
// FileItem is an example implementation of an Item | |
// that wraps a file... | |
type FileItem struct { | |
fp *os.File | |
} | |
func OpenFileItems(files ...string) []Item { | |
fileItems := make([]Item, 0) | |
for _, file := range files { | |
fp, err := os.Open(file) | |
if err != nil { | |
log.Println("Error opening file...") | |
} | |
fileItems = append(fileItems, &FileItem{fp: fp}) | |
} | |
return fileItems | |
} | |
func (fi *FileItem) Search(pattern string) *Result { | |
reg, err := regexp.CompilePOSIX(pattern) | |
if err != nil { | |
return nil | |
} | |
b, err := io.ReadAll(fi.fp) | |
if err != nil { | |
return nil | |
} | |
idx := reg.FindIndex(b) | |
if idx == nil { | |
return nil | |
} | |
return &Result{ | |
Ident: fi.fp.Name(), | |
Offsets: idx, | |
} | |
} | |
// SortedItem is an example implementation of an Item | |
// that wraps a sorted set of things... | |
type SortedItem struct { | |
name string | |
data []string | |
} | |
func OpenSortedItems(datasets [][]string) []Item { | |
sortedItems := make([]Item, 0) | |
for i, str := range datasets { | |
sortedItems = append(sortedItems, &SortedItem{ | |
name: strconv.Itoa(i), | |
data: str, | |
}) | |
} | |
return sortedItems | |
} | |
func (si *SortedItem) Len() int { | |
return len(si.data) | |
} | |
func (si *SortedItem) Less(i, j int) bool { | |
return si.data[i] < si.data[j] | |
} | |
func (si *SortedItem) Swap(i, j int) { | |
si.data[i], si.data[j] = si.data[j], si.data[i] | |
} | |
func (si *SortedItem) Search(pattern string) *Result { | |
if !sort.IsSorted(si) { | |
sort.Stable(si) | |
} | |
i, found := sort.Find(si.Len(), func(i int) int { | |
return strings.Compare(pattern, si.data[i]) | |
}) | |
if !found { | |
return nil | |
} | |
return &Result{ | |
Ident: si.name, | |
Offsets: []int{i}, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment