Convert Figma logo to code with AI

ahmetb logogo-linq

.NET LINQ capabilities in Go

3,500
224
3,500
11

Top Related Projects

17,335

💥 A Lodash-style Go library based on Go 1.18+ Generics (map, filter, contains, find...)

4,744

A modern Go utility library which provides helpers (map, find, contains, filter, ...)

1,940

🍕 Enjoy a slice! A utility library for dealing with slices and maps that focuses on type safety and performance.

Helpfully Functional Go - A useful collection of Go utilities. Designed for programmer happiness.

Quick Overview

go-linq is a powerful Go library that brings LINQ-like operations to Go slices and collections. It provides a fluent API for querying and manipulating data, allowing developers to write expressive and concise code for data processing tasks.

Pros

  • Enhances Go's standard library with a rich set of data manipulation functions
  • Supports method chaining for improved readability and expressiveness
  • Provides type-safe operations with generics support
  • Offers lazy evaluation for improved performance on large datasets

Cons

  • May introduce a learning curve for developers unfamiliar with LINQ concepts
  • Could potentially impact performance for small datasets compared to native Go operations
  • Adds an external dependency to projects
  • Some operations may be less intuitive compared to native Go slice operations

Code Examples

  1. Filtering and mapping a slice of integers:
import . "github.com/ahmetb/go-linq/v3"

numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
result := From(numbers).
    Where(func(i interface{}) bool { return i.(int) % 2 == 0 }).
    Select(func(i interface{}) interface{} { return i.(int) * 2 }).
    Results()
// result: [4, 8, 12, 16, 20]
  1. Grouping and aggregating data:
import . "github.com/ahmetb/go-linq/v3"

type Person struct {
    Name string
    Age  int
}

people := []Person{
    {"Alice", 25}, {"Bob", 30}, {"Charlie", 25}, {"David", 30},
}

result := From(people).
    GroupBy(
        func(p interface{}) interface{} { return p.(Person).Age },
        func(p interface{}) interface{} { return p.(Person) },
    ).
    Select(func(g interface{}) interface{} {
        return KeyValue{
            Key:   g.(Group).Key,
            Value: g.(Group).Group.Count(),
        }
    }).
    OrderByDescending(func(kv interface{}) interface{} {
        return kv.(KeyValue).Value
    }).
    Results()
// result: [{30 2} {25 2}]
  1. Using generics for type-safe operations:
import "github.com/ahmetb/go-linq/v3"

numbers := []int{1, 2, 3, 4, 5}
sum := linq.From(numbers).
    WhereT(func(n int) bool { return n%2 == 0 }).
    SumInts()
// sum: 6

Getting Started

To use go-linq in your Go project, follow these steps:

  1. Install the library:

    go get github.com/ahmetb/go-linq/v3
    
  2. Import the library in your Go file:

    import . "github.com/ahmetb/go-linq/v3"
    
  3. Start using LINQ operations on your slices or collections:

    numbers := []int{1, 2, 3, 4, 5}
    evenSquares := From(numbers).
        Where(func(n interface{}) bool { return n.(int)%2 == 0 }).
        Select(func(n interface{}) interface{} { return n.(int) * n.(int) }).
        Results()
    

Competitor Comparisons

17,335

💥 A Lodash-style Go library based on Go 1.18+ Generics (map, filter, contains, find...)

Pros of lo

  • More comprehensive set of utility functions, including error handling and concurrency helpers
  • Better performance in many operations due to optimized implementations
  • Active development with frequent updates and new features

Cons of lo

  • Larger API surface to learn compared to go-linq's focused LINQ-style approach
  • May introduce dependencies that some projects want to avoid
  • Less idiomatic Go in some cases, favoring functional programming paradigms

Code Comparison

go-linq:

result := From(users).
    Where(func(u interface{}) bool {
        return u.(User).Age > 18
    }).
    Select(func(u interface{}) interface{} {
        return u.(User).Name
    }).
    ToSlice()

lo:

result := lo.Filter(users, func(u User, _ int) bool {
    return u.Age > 18
})
names := lo.Map(result, func(u User, _ int) string {
    return u.Name
})

Both libraries provide similar functionality for filtering and mapping collections, but lo offers a more concise syntax and type-safe operations. go-linq follows a more fluent interface style, while lo uses separate function calls for each operation. The choice between them often depends on personal preference and specific project requirements.

4,744

A modern Go utility library which provides helpers (map, find, contains, filter, ...)

Pros of go-funk

  • More comprehensive set of utility functions, covering a wider range of operations
  • Supports both generic and non-generic implementations, offering flexibility
  • Actively maintained with regular updates and improvements

Cons of go-funk

  • May have slightly higher performance overhead due to reflection-based implementation
  • Less focused on LINQ-style operations compared to go-linq
  • Steeper learning curve due to the larger API surface

Code Comparison

go-funk:

result := funk.Filter([]int{1, 2, 3, 4}, func(x int) bool {
    return x%2 == 0
})

go-linq:

result := From([]int{1, 2, 3, 4}).Where(func(i interface{}) bool {
    return i.(int)%2 == 0
}).Results()

go-funk offers a more straightforward API for common operations, while go-linq provides a more LINQ-like syntax with method chaining. go-funk's implementation is more flexible but may have slightly lower performance due to reflection. go-linq focuses on LINQ-style querying and may be more familiar to developers coming from C# or other languages with LINQ support.

Both libraries have their strengths, and the choice between them depends on specific project requirements, performance needs, and developer preferences. go-funk is better suited for general-purpose utility functions, while go-linq excels in data querying and manipulation scenarios.

1,940

🍕 Enjoy a slice! A utility library for dealing with slices and maps that focuses on type safety and performance.

Pros of pie

  • Type-safe: Uses code generation to create type-specific functions
  • Better performance: Avoids reflection, leading to faster execution
  • Supports custom types: Can work with user-defined structs and types

Cons of pie

  • Requires code generation: Extra step in the development process
  • Limited functionality: Fewer operations compared to go-linq
  • Less flexible: Type-specific functions may lead to code duplication

Code Comparison

go-linq:

result := From(users).Where(func(u interface{}) bool {
    return u.(User).Age > 30
}).Select(func(u interface{}) interface{} {
    return u.(User).Name
}).ToSlice()

pie:

names := pie.Of(users).
    Filter(func(u User) bool { return u.Age > 30 }).
    Map(func(u User) string { return u.Name }).
    ToSlice()

Both libraries provide similar functionality for filtering and mapping data, but pie offers type-safe operations without type assertions. go-linq uses a more generic approach with interface{}, while pie generates type-specific functions. The pie example is more concise and readable, but requires code generation for each type used.

Helpfully Functional Go - A useful collection of Go utilities. Designed for programmer happiness.

Pros of go-underscore

  • Inspired by Underscore.js, providing familiar functionality for JavaScript developers
  • Includes a broader range of utility functions beyond collection manipulation
  • Simpler API with less focus on method chaining

Cons of go-underscore

  • Less actively maintained (last commit in 2014)
  • Fewer collection manipulation functions compared to go-linq
  • No support for parallel processing or lazy evaluation

Code Comparison

go-underscore:

result := underscore.Map([]int{1, 2, 3}, func(n, _ int) int {
    return n * 2
})

go-linq:

result := From([]int{1, 2, 3}).
    Select(func(n interface{}) interface{} {
        return n.(int) * 2
    }).
    Results()

Key Differences

  • go-linq focuses on LINQ-like operations and method chaining
  • go-underscore provides a broader set of utility functions
  • go-linq has better type safety and performance optimizations
  • go-underscore has a simpler API but less flexibility

Conclusion

go-linq is more suitable for complex data manipulation tasks and offers better performance, while go-underscore provides a familiar API for developers coming from JavaScript backgrounds. Consider your specific use case and team preferences when choosing between the two libraries.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

go-linq GoDoc Build Status Coverage Status Go Report Card

A powerful language integrated query (LINQ) library for Go.

  • Written in vanilla Go, no dependencies!
  • Complete lazy evaluation with iterator pattern
  • Safe for concurrent use
  • Supports generic functions to make your code cleaner and free of type assertions
  • Supports arrays, slices, maps, strings, channels and custom collections

Installation

When used with Go modules, use the following import path:

go get github.com/ahmetb/go-linq/v3

Older versions of Go using different dependency management tools can use the following import path to prevent breaking API changes:

go get gopkg.in/ahmetb/go-linq.v3

Quickstart

Usage is as easy as chaining methods like:

From(slice) .Where(predicate) .Select(selector) .Union(data)

Example 1: Find all owners of cars manufactured after 2015

import . "github.com/ahmetb/go-linq/v3"

type Car struct {
    year int
    owner, model string
}

...


var owners []string

From(cars).Where(func(c interface{}) bool {
	return c.(Car).year >= 2015
}).Select(func(c interface{}) interface{} {
	return c.(Car).owner
}).ToSlice(&owners)

Or, you can use generic functions, like WhereT and SelectT to simplify your code (at a performance penalty):

var owners []string

From(cars).WhereT(func(c Car) bool {
	return c.year >= 2015
}).SelectT(func(c Car) string {
	return c.owner
}).ToSlice(&owners)

Example 2: Find the author who has written the most books

import . "github.com/ahmetb/go-linq/v3"

type Book struct {
	id      int
	title   string
	authors []string
}

author := From(books).SelectMany( // make a flat array of authors
	func(book interface{}) Query {
		return From(book.(Book).authors)
	}).GroupBy( // group by author
	func(author interface{}) interface{} {
		return author // author as key
	}, func(author interface{}) interface{} {
		return author // author as value
	}).OrderByDescending( // sort groups by its length
	func(group interface{}) interface{} {
		return len(group.(Group).Group)
	}).Select( // get authors out of groups
	func(group interface{}) interface{} {
		return group.(Group).Key
	}).First() // take the first author

Example 3: Implement a custom method that leaves only values greater than the specified threshold

type MyQuery Query

func (q MyQuery) GreaterThan(threshold int) Query {
	return Query{
		Iterate: func() Iterator {
			next := q.Iterate()

			return func() (item interface{}, ok bool) {
				for item, ok = next(); ok; item, ok = next() {
					if item.(int) > threshold {
						return
					}
				}

				return
			}
		},
	}
}

result := MyQuery(Range(1,10)).GreaterThan(5).Results()

Generic Functions

Although Go doesn't implement generics, with some reflection tricks, you can use go-linq without typing interface{}s and type assertions. This will introduce a performance penalty (5x-10x slower) but will yield in a cleaner and more readable code.

Methods with T suffix (such as WhereT) accept functions with generic types. So instead of

.Select(func(v interface{}) interface{} {...})

you can type:

.SelectT(func(v YourType) YourOtherType {...})

This will make your code free of interface{} and type assertions.

Example 4: "MapReduce" in a slice of string sentences to list the top 5 most used words using generic functions

var results []string

From(sentences).
	// split sentences to words
	SelectManyT(func(sentence string) Query {
		return From(strings.Split(sentence, " "))
	}).
	// group the words
	GroupByT(
		func(word string) string { return word },
		func(word string) string { return word },
	).
	// order by count
	OrderByDescendingT(func(wordGroup Group) int {
		return len(wordGroup.Group)
	}).
	// order by the word
	ThenByT(func(wordGroup Group) string {
		return wordGroup.Key.(string)
	}).
	Take(5).  // take the top 5
	// project the words using the index as rank
	SelectIndexedT(func(index int, wordGroup Group) string {
		return fmt.Sprintf("Rank: #%d, Word: %s, Counts: %d", index+1, wordGroup.Key, len(wordGroup.Group))
	}).
	ToSlice(&results)

More examples can be found in the documentation.

Release Notes

v3.2.0 (2020-12-29)
* Added FromChannelT().
* Added DefaultIfEmpty().

v3.1.0 (2019-07-09)
* Support for Go modules
* Added IndexOf()/IndexOfT().

v3.0.0 (2017-01-10)
* Breaking change: ToSlice() now overwrites existing slice starting
  from index 0 and grows/reslices it as needed.
* Generic methods support (thanks @cleitonmarx!)
  - Accepting parametrized functions was originally proposed in #26
  - You can now avoid type assertions and interface{}s
  - Functions with generic methods are named as "MethodNameT" and
    signature for the existing LINQ methods are unchanged.
* Added ForEach(), ForEachIndexed() and AggregateWithSeedBy().

v2.0.0 (2016-09-02)
* IMPORTANT: This release is a BREAKING CHANGE. The old version
  is archived at the 'archive/0.9' branch or the 0.9 tags.
* A COMPLETE REWRITE of go-linq with better performance and memory
  efficiency. (thanks @kalaninja!)
* API has significantly changed. Most notably:
  - linq.T removed in favor of interface{}
  - library methods no longer return errors
  - PLINQ removed for now (see channels support)
  - support for channels, custom collections and comparables

v0.9-rc4
* GroupBy()

v0.9-rc3.2
* bugfix: All() iterating over values instead of indices

v0.9-rc3.1
* bugfix: modifying result slice affects subsequent query methods

v0.9-rc3
* removed FirstOrNil, LastOrNil, ElementAtOrNil methods

v0.9-rc2.5
* slice-accepting methods accept slices of any type with reflections

v0.9-rc2
* parallel linq (plinq) implemented
* Queryable separated into Query & ParallelQuery
* fixed early termination for All

v0.9-rc1
* many linq methods are implemented
* methods have error handling support
* type assertion limitations are unresolved
* travis-ci.org build integrated
* open sourced on github, master & dev branches