iter2

package module
v0.0.0-...-0a8d322 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2025 License: MIT Imports: 6 Imported by: 0

README

iter2

Go iter utilities.

  1. Operations of iterator:

    Zipping two Seqs to one Seq of pairs:

    func ExampleZip() {
        ks := []int{1, 2, 3}
        vs := []string{"one", "two", "three"}
    
        type pair struct {
            N   int
            Str string
        }
    
        s := slices.Collect(iter2.Zip(slices.Values(ks), slices.Values(vs), func(i int, s string) pair { return pair{i, s} }))
        fmt.Println(s)
        // Output: [{1 one} {2 two} {3 three}]
    }
    

    Zipping tow Seqs to one Seq2:

    func ExampleZip2() {
        ks := []int{1, 2, 3}
        vs := []string{"one", "two", "three"}
        zipped := iter2.Zip2(slices.Values(ks), slices.Values(vs))
        m := maps.Collect(zipped)
        for k, v := range m {
            fmt.Println(k, v)
        }
        // Unordered output:
        // 1 one
        // 2 two
        // 3 three
    }
    

    Concating 2 Seqs:

    func ExampleConcat() {
        seq1 := slices.Values([]int{1, 2, 3})
        seq2 := slices.Values([]int{4, 5})
        seq := iter2.Concat(seq1, seq2)
        fmt.Println(slices.Collect(seq))
        // Output:
        // [1 2 3 4 5]
    }
    
  2. Map DB rows:

    import (
        "database/sql"
        _ "modernc.org/sqlite"
        // and more
    )
    
    func ExampleAllRows_tableStruct() {
        db, err := sql.Open("sqlite", ":memory:")
        if err != nil {
            panic(err)
        }
        q := `
    create temp table users (id integer, name text); -- Create temp table for queries.
    insert into users values (1, "User1"); -- Populate temp table.
    insert into users values (2, "User2");
    insert into users values (3, "User3");
    
    -- First result set.
    select * from users;
    `
        type User struct {
            ID   int
            Name string
        }
    
        users := slices.Collect(
            iter2.Map(
                iter2.MustAllRows(db.Query(q)), func(row iter2.Row) (user User) {
                    row.Scan(&user.ID, &user.Name)
                    return
                }))
        fmt.Println(users)
        // Should output:
        // [{1 User1} {2 User2} {3 User3}]
    }
    

More examples here.

Documentation

Overview

Package iter2 implements iter utilities.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllRows

func AllRows(rows *sql.Rows) iter.Seq[Row]

All returns an iterator over rows in the *sql.Rows.

Example
package main

import (
	"database/sql"
	"fmt"

	"github.com/mkch/iter2"
)

func main() {
	var db *sql.DB // Open db.
	q := `
-- Create temp table for queries.
create temp table uid (id bigint);
-- Populate temp table. 
insert into uid values (1); 
insert into uid values (2);
insert into uid values (3);
-- Do query.
select * from uid order by id;
`
	r, err := db.Query(q)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	for row := range iter2.AllRows(r) {
		var id int
		row.Scan(&id)
		fmt.Println(id)
	}
	// Should output:
	// 1
	// 2
	// 3
}
Example (TableStruct)
package main

import (
	"database/sql"
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	db, err := sql.Open("sqlite", ":memory:")
	if err != nil {
		panic(err)
	}
	q := `
create temp table users (id integer, name text); -- Create temp table for queries.
insert into users values (1, "User1"); -- Populate temp table.
insert into users values (2, "User2");
insert into users values (3, "User3");

-- First result set.
select * from users;
`
	type User struct {
		ID   int
		Name string
	}

	users := slices.Collect(
		iter2.Map(
			iter2.MustAllRows(db.Query(q)), func(row iter2.Row) (user User) {
				row.Scan(&user.ID, &user.Name)
				return
			}))
	fmt.Println(users)
	// Should output:
	// [{1 User1} {2 User2} {3 User3}]
}

func Concat

func Concat[T any](seqs ...iter.Seq[T]) iter.Seq[T]

Concat returns the concation of seqs. Concat yields the values from seqs without interleaving them.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	seq1 := slices.Values([]int{1, 2, 3})
	seq2 := slices.Values([]int{4, 5})
	seq := iter2.Concat(seq1, seq2)
	fmt.Println(slices.Collect(seq))
}
Output:

[1 2 3 4 5]

func Empty

func Empty[V any](yield func(V) bool)

Empty is an empty iterator yields no value.

func Empty2

func Empty2[K, V any](yield func(K, V) bool)

Empty is an empty iterator yields no key-value pair.

func Filter

func Filter[T any](seq iter.Seq[T], test func(T) bool) iter.Seq[T]

Filter returns an iterator over the sequence of elements in seq that pass the test.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	s := []int{1, 2, 3, 4}
	even := iter2.Filter(slices.Values(s),
		func(n int) bool { return n%2 == 0 })
	fmt.Println(slices.Collect(even))
}
Output:

[2 4]

func Filter2

func Filter2[K, V any](seq iter.Seq2[K, V], test func(K, V) bool) iter.Seq2[K, V]

Filter returns an iterator over the sequence of elements in seq that pass the test.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	s := []int{1, 2, 3, 4}
	even := iter2.Filter2(slices.All(s),
		func(i, n int) bool { return n%2 == 0 })
	for i, n := range even {
		fmt.Println(i, n)
	}
}
Output:

1 2
3 4

func Just

func Just[V any](values ...V) iter.Seq[V]

Just returns an iterator over values.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	seq := iter2.Just(1, 2, 3)
	fmt.Println(slices.Collect(seq))
}
Output:

[1 2 3]

func Just2

func Just2[K, V any](pairs ...struct {
	K K
	V V
}) iter.Seq2[K, V]

Just returns an iterator over key-value pairs.

Example
package main

import (
	"fmt"

	"github.com/mkch/iter2"
)

func main() {
	type KV = struct {
		K int
		V string
	}
	seq := iter2.Just2(KV{1, "one"}, KV{2, "two"})
	for k, v := range seq {
		fmt.Println(k, v)
	}
}
Output:

1 one
2 two

func Keys

func Keys[K, V any](seq2 iter.Seq2[K, V]) iter.Seq[K]

Keys returns an iterator over keys in seq2.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	seq2 := func(yield func(int, string) bool) {
		if !yield(0, "zero") {
			return
		}
		if !yield(1, "one") {
			return
		}
	}
	keys := iter2.Keys(seq2)
	fmt.Println(slices.Collect(keys))
}
Output:

[0 1]

func Map

func Map[T1, T2 any](seq iter.Seq[T1], f func(T1) T2) iter.Seq[T2]

Map returns an iter.Seq that contains a sequence transformed form seq by func f.

Example
package main

import (
	"fmt"
	"slices"
	"strconv"

	"github.com/mkch/iter2"
)

func main() {
	iter := slices.Values([]int{1, 2, 3})
	seq := iter2.Map(iter, func(v int) string { return strconv.Itoa(v + 1) })
	fmt.Printf("%q", slices.Collect(seq))
}
Output:

["2" "3" "4"]

func Map1To2

func Map1To2[T, K, V any](seq iter.Seq[T], f func(v T) (K, V)) iter.Seq2[K, V]

Map1To2 returns an iter.Seq2 that contains a sequence transformed form seq by func f.

Example
package main

import (
	"fmt"
	"slices"
	"strconv"

	"github.com/mkch/iter2"
)

func main() {
	seq1 := slices.Values([]int{1, 2, 3})
	seq2 := iter2.Map1To2(seq1, func(v int) (byte, string) { return byte(v), strconv.Itoa(v) })
	for k, v := range seq2 {
		fmt.Printf("%v %q\n", k, v)
	}
}
Output:

1 "1"
2 "2"
3 "3"

func Map2

func Map2[K1, V1, K2, V2 any](seq iter.Seq2[K1, V1], f func(K1, V1) (K2, V2)) iter.Seq2[K2, V2]

Map returns an iter.Seq2 that contains a sequence transformed form seq by func f.

Example
package main

import (
	"fmt"
	"slices"
	"strings"

	"github.com/mkch/iter2"
)

func main() {
	iter := slices.All([]int{1, 2, 3})
	seq := iter2.Map2(iter, func(i int, v int) (int, string) { return i + 1, strings.Repeat("a", v) })
	for k, v := range seq {
		fmt.Printf("%v %q\n", k, v)
	}
}
Output:

1 "a"
2 "aa"
3 "aaa"

func Map2To1

func Map2To1[T, K, V any](seq iter.Seq2[K, V], f func(K, V) T) iter.Seq[T]

Map2To1 returns an iter.Seq that contains a sequence transformed form seq by func f.

func Merge

func Merge[T any](seqs ...iter.Seq[T]) iter.Seq[T]

Merge combines seqs into one by merging their values. Merge may interleave the values yield by the merged Seq. A similar func Concat does not interleave values, but yields all of each source Seq's values in turn before beginning to yield values from the next source Seq.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	seq1 := slices.Values([]int{1, 2, 3})
	seq2 := slices.Values([]int{4, 5})
	seq := iter2.Merge(seq1, seq2)
	for v := range seq {
		fmt.Println(v)
	}
}
Output:

1
2
3
4
5

func MustAllRows

func MustAllRows(rows *sql.Rows, err error) iter.Seq[Row]

MustAllRows is similar to the AllRows, but with two differences: 1. It has an additional err parameter. If err is not nil, MustAllRows will call panic(err). Otherwise, it calls AllRows(rows) and returns its result. 2. Once the returned Seq is iterated, it will call rows.Close() when done.

MustAllRows is convenient when calling with Query of sql. For example:

seq := iter2.MustAllRows(db.Query(q))

func Push

func Push[T any]() (seq iter.Seq[T], yield func(T) bool, stop func())

Push creates an iterator whose values are yielded by function calls. Calling yield pushes the next value onto the sequence, stopping early if yield returns false. Stop ends the iteration. It must be called when the caller has no next value to push. It is valid to call stop multiple times. Typically, callers should “defer stop()”. It is safe to call yield and stop from multiple goroutines simultaneously.

Push is useful when yielding values out of a loop.

Example
package main

import (
	"fmt"
	"time"

	"github.com/mkch/iter2"
)

func main() {
	seq, yield, stop := iter2.Push[int]()
	defer stop()
	time.AfterFunc(time.Millisecond*1, func() {
		yield(1)
		time.AfterFunc(time.Millisecond*1, func() {
			yield(2)
			stop()
		})
	})

	for t := range seq {
		fmt.Println(t)
	}
}
Output:

1
2

func Push2

func Push2[K, V any]() (seq2 iter.Seq2[K, V], yield func(K, V) bool, stop func())

Push2 creates an iterator whose values are yielded by function calls. Push2 works the same way as Push, except for the type parameters.

func Take

func Take[T any](seq iter.Seq[T], n int) iter.Seq[T]

Take returns an iterator that yields the first n values in seq. Take panics if n < 0.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	seq := slices.Values([]int{1, 2, 3, 4, 5})
	seq = iter2.Take(seq, 2)
	fmt.Println(slices.Collect(seq))
}
Output:

[1 2]

func Take2

func Take2[K, V any](seq2 iter.Seq2[K, V], n int) iter.Seq2[K, V]

Take returns an iterator that yields the first n values in seq2. Take panics if n < 0.

func TokenStrings

func TokenStrings(scanner *bufio.Scanner) iter.Seq[string]

TokenStrings returns an iterator over token strings scanned by the scanner.

Example
package main

import (
	"bufio"
	"fmt"
	"strings"

	"github.com/mkch/iter2"
)

func main() {
	r := bufio.NewScanner(strings.NewReader("Some words here"))
	r.Split(bufio.ScanWords)
	lines := iter2.TokenStrings(r)
	for line := range lines {
		fmt.Printf("%s\n", line)
	}
}
Output:

Some
words
here

func Tokens

func Tokens(scanner *bufio.Scanner) iter.Seq[[]byte]

Tokens returns an iterator over tokens scanned by the scanner.

Example
package main

import (
	"bufio"
	"fmt"
	"strings"

	"github.com/mkch/iter2"
)

func main() {
	r := bufio.NewScanner(strings.NewReader("abc\ndef"))
	lines := iter2.Tokens(r)
	for line := range lines {
		fmt.Printf("%s\n", line)
	}
}
Output:

abc
def

func Values

func Values[K, V any](seq2 iter.Seq2[K, V]) iter.Seq[V]

Keys returns an iterator over values in seq2.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	seq2 := func(yield func(int, string) bool) {
		if !yield(0, "zero") {
			return
		}
		if !yield(1, "one") {
			return
		}
	}
	values := iter2.Values(seq2)
	fmt.Println(slices.Collect(values))
}
Output:

[zero one]

func WalkDir

func WalkDir(fsys fs.FS, root string) iter.Seq2[*DirEntry, error]

WalkDir returns an iterator over the file tree rooted at root.

Example
package main

import (
	"fmt"
	"os"

	"github.com/mkch/iter2"
)

func main() {
	dirs := iter2.WalkDir(os.DirFS("testdata"), ".")
	for d, err := range dirs {
		if err != nil {
			continue // continue to ignore the error
		}
		if d.Path == "should_skip" {
			d.SkipDir()
			continue
		}
		fmt.Printf("Walk: %v\n", d.Path)
	}
}

func Zip

func Zip[T1, T2, Pair any](seq1 iter.Seq[T1], seq2 iter.Seq[T2], pair func(v1 T1, v2 T2) Pair) iter.Seq[Pair]

Zip returns an iter.Seq that pairs corresponding elements from iter1 and iter2. Iteration stops when either of the seq1 or seq2 stops.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	ks := []int{1, 2, 3}
	vs := []string{"one", "two", "three"}

	type pair struct {
		N   int
		Str string
	}

	s := slices.Collect(iter2.Zip(slices.Values(ks), slices.Values(vs), func(i int, s string) pair { return pair{i, s} }))
	fmt.Println(s)
}
Output:

[{1 one} {2 two} {3 three}]

func Zip2

func Zip2[T1, T2 any](seq1 iter.Seq[T1], seq2 iter.Seq[T2]) iter.Seq2[T1, T2]

Zip2 returns an iter.Seq2 that pairs corresponding elements from iter1 and iter2. Iteration stops when either of the seq1 or seq2 stops.

Example
package main

import (
	"fmt"
	"maps"
	"slices"

	"github.com/mkch/iter2"
)

func main() {
	ks := []int{1, 2, 3}
	vs := []string{"one", "two", "three"}
	zipped := iter2.Zip2(slices.Values(ks), slices.Values(vs))
	m := maps.Collect(zipped)
	for k, v := range m {
		fmt.Println(k, v)
	}
}
Output:

1 one
2 two
3 three

Types

type DirEntry

type DirEntry struct {
	// Path contains the argument to WalkDir as a prefix. That is, if WalkDir is called with root argument "dir"
	// and finds a file named "a" in that directory, the Path of yielded DirEntry is "dir/a".
	Path string
	// Entry is the [fs.DirEntry] for the named path.
	Entry fs.DirEntry
	// contains filtered or unexported fields
}

DirEntry is a file or directory of a file tree.

func (*DirEntry) SkipAll

func (dir *DirEntry) SkipAll()

SkipAll skips all remaining files and directories.

func (*DirEntry) SkipDir

func (dir *DirEntry) SkipDir()

SkipDir skips the current directory (path if d.IsDir() is true, otherwise path's parent directory).

type Row

type Row struct {
	// contains filtered or unexported fields
}

Row is a row of sql.Rows.

func (Row) Scan

func (row Row) Scan(dest ...any) error

Scan copies the columns in the current row into the values pointed at by dest. See Scan method of sql.Rows.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL