forked from Snider/Poindexter
Merge pull request #1 from Snider/copilot/fix-631881-1088881000-1ebcc534-1620-4cc1-a3b4-d4aabc78c0dc
Bootstrap Go library with EUPL-1.2, goreleaser, mkdocs-material, and sorting utilities
This commit is contained in:
commit
dbcad82d6b
17 changed files with 1551 additions and 1 deletions
30
.github/workflows/docs.yml
vendored
Normal file
30
.github/workflows/docs.yml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
name: Deploy Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install mkdocs-material
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
run: |
|
||||
mkdocs gh-deploy --force
|
||||
32
.github/workflows/release.yml
vendored
Normal file
32
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
33
.github/workflows/test.yml
vendored
Normal file
33
.github/workflows/test.yml
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
|
||||
- name: Run tests
|
||||
run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./coverage.txt
|
||||
fail_ci_if_error: false
|
||||
58
.gitignore
vendored
Normal file
58
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
# Build output
|
||||
dist/
|
||||
build/
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# MkDocs
|
||||
site/
|
||||
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.DS_Store
|
||||
71
.goreleaser.yml
Normal file
71
.goreleaser.yml
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
|
||||
# The lines below are called `modelines`. See `:help modeline`
|
||||
# Feel free to remove those if you don't want/need to use them.
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
# you may remove this if you don't need go generate
|
||||
- go generate ./...
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
# Optional: Exclude specific combinations
|
||||
ignore:
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
# this name template makes the OS and Arch compatible with the results of `uname`.
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- title .Os }}_
|
||||
{{- if eq .Arch "amd64" }}x86_64
|
||||
{{- else if eq .Arch "386" }}i386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
||||
# use zip for windows archives
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
- "^ci:"
|
||||
- "^chore:"
|
||||
- "^build:"
|
||||
- Merge pull request
|
||||
- Merge branch
|
||||
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
|
||||
snapshot:
|
||||
version_template: "{{ incpatch .Version }}-next"
|
||||
|
||||
release:
|
||||
github:
|
||||
owner: Snider
|
||||
name: Poindexter
|
||||
draft: false
|
||||
prerelease: auto
|
||||
190
LICENSE
Normal file
190
LICENSE
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
||||
EUPL © the European Union 2007, 2016
|
||||
|
||||
This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined below) which is provided under the
|
||||
terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such
|
||||
use is covered by a right of the copyright holder of the Work).
|
||||
The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following
|
||||
notice immediately following the copyright notice for the Work:
|
||||
Licensed under the EUPL
|
||||
or has expressed by any other means his willingness to license under the EUPL.
|
||||
|
||||
1.Definitions
|
||||
In this Licence, the following terms have the following meaning:
|
||||
— ‘The Licence’:this Licence.
|
||||
— ‘The Original Work’:the work or software distributed or communicated by the Licensor under this Licence, available
|
||||
as Source Code and also as Executable Code as the case may be.
|
||||
— ‘Derivative Works’:the works or software that could be created by the Licensee, based upon the Original Work or
|
||||
modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work
|
||||
required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in
|
||||
the country mentioned in Article 15.
|
||||
— ‘The Work’:the Original Work or its Derivative Works.
|
||||
— ‘The Source Code’:the human-readable form of the Work which is the most convenient for people to study and
|
||||
modify.
|
||||
— ‘The Executable Code’:any code which has generally been compiled and which is meant to be interpreted by
|
||||
a computer as a program.
|
||||
— ‘The Licensor’:the natural or legal person that distributes or communicates the Work under the Licence.
|
||||
— ‘Contributor(s)’:any natural or legal person who modifies the Work under the Licence, or otherwise contributes to
|
||||
the creation of a Derivative Work.
|
||||
— ‘The Licensee’ or ‘You’:any natural or legal person who makes any usage of the Work under the terms of the
|
||||
Licence.
|
||||
— ‘Distribution’ or ‘Communication’:any act of selling, giving, lending, renting, distributing, communicating,
|
||||
transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential
|
||||
functionalities at the disposal of any other natural or legal person.
|
||||
|
||||
2.Scope of the rights granted by the Licence
|
||||
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for
|
||||
the duration of copyright vested in the Original Work:
|
||||
— use the Work in any circumstance and for all usage,
|
||||
— reproduce the Work,
|
||||
— modify the Work, and make Derivative Works based upon the Work,
|
||||
— communicate to the public, including the right to make available or display the Work or copies thereof to the public
|
||||
and perform publicly, as the case may be, the Work,
|
||||
— distribute the Work or copies thereof,
|
||||
— lend and rent the Work or copies thereof,
|
||||
— sublicense rights in the Work or copies thereof.
|
||||
Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the
|
||||
applicable law permits so.
|
||||
In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed
|
||||
by law in order to make effective the licence of the economic rights here above listed.
|
||||
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the
|
||||
extent necessary to make use of the rights granted on the Work under this Licence.
|
||||
|
||||
3.Communication of the Source Code
|
||||
The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as
|
||||
Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with
|
||||
each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to
|
||||
the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to
|
||||
distribute or communicate the Work.
|
||||
|
||||
4.Limitations on copyright
|
||||
Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the
|
||||
exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations
|
||||
thereto.
|
||||
|
||||
5.Obligations of the Licensee
|
||||
The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those
|
||||
obligations are the following:
|
||||
|
||||
Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to
|
||||
the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the
|
||||
Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work
|
||||
to carry prominent notices stating that the Work has been modified and the date of modification.
|
||||
|
||||
Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this
|
||||
Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless
|
||||
the Original Work is expressly distributed only under this version of the Licence — for example by communicating
|
||||
‘EUPL v. 1.2 only’. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the
|
||||
Work or Derivative Work that alter or restrict the terms of the Licence.
|
||||
|
||||
Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both
|
||||
the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done
|
||||
under the terms of this Compatible Licence. For the sake of this clause, ‘Compatible Licence’ refers to the licences listed
|
||||
in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with
|
||||
his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail.
|
||||
|
||||
Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide
|
||||
a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available
|
||||
for as long as the Licensee continues to distribute or communicate the Work.
|
||||
Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names
|
||||
of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the copyright notice.
|
||||
|
||||
6.Chain of Authorship
|
||||
The original Licensor warrants that the copyright in the Original Work granted hereunder is owned by him/her or
|
||||
licensed to him/her and that he/she has the power and authority to grant the Licence.
|
||||
Each Contributor warrants that the copyright in the modifications he/she brings to the Work are owned by him/her or
|
||||
licensed to him/her and that he/she has the power and authority to grant the Licence.
|
||||
Each time You accept the Licence, the original Licensor and subsequent Contributors grant You a licence to their contributions
|
||||
to the Work, under the terms of this Licence.
|
||||
|
||||
7.Disclaimer of Warranty
|
||||
The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work
|
||||
and may therefore contain defects or ‘bugs’ inherent to this type of development.
|
||||
For the above reason, the Work is provided under the Licence on an ‘as is’ basis and without warranties of any kind
|
||||
concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or
|
||||
errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this
|
||||
Licence.
|
||||
This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work.
|
||||
|
||||
8.Disclaimer of Liability
|
||||
Except in the cases of wilful misconduct or damages directly caused to natural persons, the Licensor will in no event be
|
||||
liable for any direct or indirect, material or moral, damages of any kind, arising out of the Licence or of the use of the
|
||||
Work, including without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss
|
||||
of data or any commercial damage, even if the Licensor has been advised of the possibility of such damage. However,
|
||||
the Licensor will be liable under statutory product liability laws as far such laws apply to the Work.
|
||||
|
||||
9.Additional agreements
|
||||
While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services
|
||||
consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole
|
||||
responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by
|
||||
the fact You have accepted any warranty or additional liability.
|
||||
|
||||
10.Acceptance of the Licence
|
||||
The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ placed under the bottom of a window
|
||||
displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of
|
||||
applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms
|
||||
and conditions.
|
||||
Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You
|
||||
by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution
|
||||
or Communication by You of the Work or copies thereof.
|
||||
|
||||
11.Information to the public
|
||||
In case of any Distribution or Communication of the Work by means of electronic communication by You (for example,
|
||||
by offering to download the Work from a remote location) the distribution channel or media (for example, a website)
|
||||
must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence
|
||||
and the way it may be accessible, concluded, stored and reproduced by the Licensee.
|
||||
|
||||
12.Termination of the Licence
|
||||
The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms
|
||||
of the Licence.
|
||||
Such a termination will not terminate the licences of any person who has received the Work from the Licensee under
|
||||
the Licence, provided such persons remain in full compliance with the Licence.
|
||||
|
||||
13.Miscellaneous
|
||||
Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the
|
||||
Work.
|
||||
If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or
|
||||
enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid
|
||||
and enforceable.
|
||||
The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of
|
||||
the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence.
|
||||
New versions of the Licence will be published with a unique version number.
|
||||
All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take
|
||||
advantage of the linguistic version of their choice.
|
||||
|
||||
14.Jurisdiction
|
||||
Without prejudice to specific agreement between parties,
|
||||
— any litigation resulting from the interpretation of this License, arising between the European Union institutions,
|
||||
bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice
|
||||
of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union,
|
||||
— any litigation arising between other parties and resulting from the interpretation of this License, will be subject to
|
||||
the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business.
|
||||
|
||||
15.Applicable Law
|
||||
Without prejudice to specific agreement between parties,
|
||||
— this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat,
|
||||
resides or has his registered office,
|
||||
— this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside
|
||||
a European Union Member State.
|
||||
|
||||
|
||||
Appendix
|
||||
|
||||
‘Compatible Licences’ according to Article 5 EUPL are:
|
||||
— GNU General Public License (GPL) v. 2, v. 3
|
||||
— GNU Affero General Public License (AGPL) v. 3
|
||||
— Open Software License (OSL) v. 2.1, v. 3.0
|
||||
— Eclipse Public License (EPL) v. 1.0
|
||||
— CeCILL v. 2.0, v. 2.1
|
||||
— Mozilla Public Licence (MPL) v. 2
|
||||
— GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
||||
— Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software
|
||||
— European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
||||
— Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+).
|
||||
|
||||
The European Commission may update this Appendix to later versions of the above licences without producing
|
||||
a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the
|
||||
covered Source Code from exclusive appropriation.
|
||||
All other changes or additions to this Appendix require the production of a new EUPL version.
|
||||
65
README.md
65
README.md
|
|
@ -1 +1,64 @@
|
|||
# Poindexter
|
||||
# Poindexter
|
||||
|
||||
A Go library package providing utility functions including sorting algorithms with custom comparators.
|
||||
|
||||
## Features
|
||||
|
||||
- 🔢 **Sorting Utilities**: Sort integers, strings, and floats in ascending or descending order
|
||||
- 🎯 **Custom Sorting**: Sort any type with custom comparison functions or key extractors
|
||||
- 🔍 **Binary Search**: Fast search on sorted data
|
||||
- 📦 **Generic Functions**: Type-safe operations using Go generics
|
||||
- ✅ **Well-Tested**: Comprehensive test coverage
|
||||
- 📖 **Documentation**: Full documentation available at GitHub Pages
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
go get github.com/Snider/Poindexter
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Snider/Poindexter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Basic sorting
|
||||
numbers := []int{3, 1, 4, 1, 5, 9}
|
||||
poindexter.SortInts(numbers)
|
||||
fmt.Println(numbers) // [1 1 3 4 5 9]
|
||||
|
||||
// Custom sorting with key function
|
||||
type Product struct {
|
||||
Name string
|
||||
Price float64
|
||||
}
|
||||
|
||||
products := []Product{
|
||||
{"Apple", 1.50},
|
||||
{"Banana", 0.75},
|
||||
{"Cherry", 3.00},
|
||||
}
|
||||
|
||||
poindexter.SortByKey(products, func(p Product) float64 {
|
||||
return p.Price
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Full documentation is available at [https://snider.github.io/Poindexter/](https://snider.github.io/Poindexter/)
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the European Union Public Licence v1.2 (EUPL-1.2). See [LICENSE](LICENSE) for details.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
318
docs/api.md
Normal file
318
docs/api.md
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
# API Reference
|
||||
|
||||
Complete API documentation for the Poindexter library.
|
||||
|
||||
## Core Functions
|
||||
|
||||
### Version
|
||||
|
||||
```go
|
||||
func Version() string
|
||||
```
|
||||
|
||||
Returns the current version of the library.
|
||||
|
||||
**Returns:**
|
||||
- `string`: The version string (e.g., "0.1.0")
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
version := poindexter.Version()
|
||||
fmt.Println(version) // Output: 0.1.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Hello
|
||||
|
||||
```go
|
||||
func Hello(name string) string
|
||||
```
|
||||
|
||||
Returns a greeting message.
|
||||
|
||||
**Parameters:**
|
||||
- `name` (string): The name to greet. If empty, defaults to "World"
|
||||
|
||||
**Returns:**
|
||||
- `string`: A greeting message
|
||||
|
||||
**Examples:**
|
||||
|
||||
```go
|
||||
// Greet the world
|
||||
message := poindexter.Hello("")
|
||||
fmt.Println(message) // Output: Hello, World!
|
||||
|
||||
// Greet a specific person
|
||||
message = poindexter.Hello("Alice")
|
||||
fmt.Println(message) // Output: Hello, Alice!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sorting Functions
|
||||
|
||||
### Basic Sorting
|
||||
|
||||
#### SortInts
|
||||
|
||||
```go
|
||||
func SortInts(data []int)
|
||||
```
|
||||
|
||||
Sorts a slice of integers in ascending order in place.
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
numbers := []int{3, 1, 4, 1, 5, 9}
|
||||
poindexter.SortInts(numbers)
|
||||
fmt.Println(numbers) // Output: [1 1 3 4 5 9]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### SortIntsDescending
|
||||
|
||||
```go
|
||||
func SortIntsDescending(data []int)
|
||||
```
|
||||
|
||||
Sorts a slice of integers in descending order in place.
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
numbers := []int{3, 1, 4, 1, 5, 9}
|
||||
poindexter.SortIntsDescending(numbers)
|
||||
fmt.Println(numbers) // Output: [9 5 4 3 1 1]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### SortStrings
|
||||
|
||||
```go
|
||||
func SortStrings(data []string)
|
||||
```
|
||||
|
||||
Sorts a slice of strings in ascending order in place.
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
words := []string{"banana", "apple", "cherry"}
|
||||
poindexter.SortStrings(words)
|
||||
fmt.Println(words) // Output: [apple banana cherry]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### SortStringsDescending
|
||||
|
||||
```go
|
||||
func SortStringsDescending(data []string)
|
||||
```
|
||||
|
||||
Sorts a slice of strings in descending order in place.
|
||||
|
||||
---
|
||||
|
||||
#### SortFloat64s
|
||||
|
||||
```go
|
||||
func SortFloat64s(data []float64)
|
||||
```
|
||||
|
||||
Sorts a slice of float64 values in ascending order in place.
|
||||
|
||||
---
|
||||
|
||||
#### SortFloat64sDescending
|
||||
|
||||
```go
|
||||
func SortFloat64sDescending(data []float64)
|
||||
```
|
||||
|
||||
Sorts a slice of float64 values in descending order in place.
|
||||
|
||||
---
|
||||
|
||||
### Advanced Sorting
|
||||
|
||||
#### SortBy
|
||||
|
||||
```go
|
||||
func SortBy[T any](data []T, less func(i, j int) bool)
|
||||
```
|
||||
|
||||
Sorts a slice using a custom comparison function.
|
||||
|
||||
**Parameters:**
|
||||
- `data`: The slice to sort
|
||||
- `less`: A function that returns true if data[i] should come before data[j]
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{"Alice", 30},
|
||||
{"Bob", 25},
|
||||
{"Charlie", 35},
|
||||
}
|
||||
|
||||
// Sort by age
|
||||
poindexter.SortBy(people, func(i, j int) bool {
|
||||
return people[i].Age < people[j].Age
|
||||
})
|
||||
// Result: [Bob(25) Alice(30) Charlie(35)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### SortByKey
|
||||
|
||||
```go
|
||||
func SortByKey[T any, K int | float64 | string](data []T, key func(T) K)
|
||||
```
|
||||
|
||||
Sorts a slice by extracting a comparable key from each element in ascending order.
|
||||
|
||||
**Parameters:**
|
||||
- `data`: The slice to sort
|
||||
- `key`: A function that extracts a sortable key from each element
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
type Product struct {
|
||||
Name string
|
||||
Price float64
|
||||
}
|
||||
|
||||
products := []Product{
|
||||
{"Apple", 1.50},
|
||||
{"Banana", 0.75},
|
||||
{"Cherry", 3.00},
|
||||
}
|
||||
|
||||
// Sort by price
|
||||
poindexter.SortByKey(products, func(p Product) float64 {
|
||||
return p.Price
|
||||
})
|
||||
// Result: [Banana(0.75) Apple(1.50) Cherry(3.00)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### SortByKeyDescending
|
||||
|
||||
```go
|
||||
func SortByKeyDescending[T any, K int | float64 | string](data []T, key func(T) K)
|
||||
```
|
||||
|
||||
Sorts a slice by extracting a comparable key from each element in descending order.
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
type Student struct {
|
||||
Name string
|
||||
Score int
|
||||
}
|
||||
|
||||
students := []Student{
|
||||
{"Alice", 85},
|
||||
{"Bob", 92},
|
||||
{"Charlie", 78},
|
||||
}
|
||||
|
||||
// Sort by score descending
|
||||
poindexter.SortByKeyDescending(students, func(s Student) int {
|
||||
return s.Score
|
||||
})
|
||||
// Result: [Bob(92) Alice(85) Charlie(78)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Checking if Sorted
|
||||
|
||||
#### IsSorted
|
||||
|
||||
```go
|
||||
func IsSorted(data []int) bool
|
||||
```
|
||||
|
||||
Checks if a slice of integers is sorted in ascending order.
|
||||
|
||||
---
|
||||
|
||||
#### IsSortedStrings
|
||||
|
||||
```go
|
||||
func IsSortedStrings(data []string) bool
|
||||
```
|
||||
|
||||
Checks if a slice of strings is sorted in ascending order.
|
||||
|
||||
---
|
||||
|
||||
#### IsSortedFloat64s
|
||||
|
||||
```go
|
||||
func IsSortedFloat64s(data []float64) bool
|
||||
```
|
||||
|
||||
Checks if a slice of float64 values is sorted in ascending order.
|
||||
|
||||
---
|
||||
|
||||
### Binary Search
|
||||
|
||||
#### BinarySearch
|
||||
|
||||
```go
|
||||
func BinarySearch(data []int, target int) int
|
||||
```
|
||||
|
||||
Performs a binary search on a sorted slice of integers.
|
||||
|
||||
**Parameters:**
|
||||
- `data`: A sorted slice of integers
|
||||
- `target`: The value to search for
|
||||
|
||||
**Returns:**
|
||||
- `int`: The index where target is found, or -1 if not found
|
||||
|
||||
**Example:**
|
||||
|
||||
```go
|
||||
numbers := []int{1, 3, 5, 7, 9, 11}
|
||||
index := poindexter.BinarySearch(numbers, 7)
|
||||
fmt.Println(index) // Output: 3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### BinarySearchStrings
|
||||
|
||||
```go
|
||||
func BinarySearchStrings(data []string, target string) int
|
||||
```
|
||||
|
||||
Performs a binary search on a sorted slice of strings.
|
||||
|
||||
**Parameters:**
|
||||
- `data`: A sorted slice of strings
|
||||
- `target`: The value to search for
|
||||
|
||||
**Returns:**
|
||||
- `int`: The index where target is found, or -1 if not found
|
||||
125
docs/getting-started.md
Normal file
125
docs/getting-started.md
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
# Getting Started
|
||||
|
||||
This guide will help you get started with the Poindexter library.
|
||||
|
||||
## Installation
|
||||
|
||||
To install Poindexter, use `go get`:
|
||||
|
||||
```bash
|
||||
go get github.com/Snider/Poindexter
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Importing the Library
|
||||
|
||||
```go
|
||||
import "github.com/Snider/Poindexter"
|
||||
```
|
||||
|
||||
### Using the Hello Function
|
||||
|
||||
The `Hello` function returns a greeting message:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Snider/Poindexter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Say hello to the world
|
||||
fmt.Println(poindexter.Hello(""))
|
||||
// Output: Hello, World!
|
||||
|
||||
// Say hello to someone specific
|
||||
fmt.Println(poindexter.Hello("Poindexter"))
|
||||
// Output: Hello, Poindexter!
|
||||
}
|
||||
```
|
||||
|
||||
### Getting the Version
|
||||
|
||||
You can check the library version:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Snider/Poindexter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
version := poindexter.Version()
|
||||
fmt.Println("Library version:", version)
|
||||
}
|
||||
```
|
||||
|
||||
## Sorting Data
|
||||
|
||||
Poindexter includes comprehensive sorting utilities:
|
||||
|
||||
### Basic Sorting
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Snider/Poindexter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Sort integers
|
||||
numbers := []int{3, 1, 4, 1, 5, 9}
|
||||
poindexter.SortInts(numbers)
|
||||
fmt.Println(numbers) // [1 1 3 4 5 9]
|
||||
|
||||
// Sort strings
|
||||
words := []string{"banana", "apple", "cherry"}
|
||||
poindexter.SortStrings(words)
|
||||
fmt.Println(words) // [apple banana cherry]
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Sorting with Custom Keys
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Snider/Poindexter"
|
||||
)
|
||||
|
||||
type Product struct {
|
||||
Name string
|
||||
Price float64
|
||||
}
|
||||
|
||||
func main() {
|
||||
products := []Product{
|
||||
{"Apple", 1.50},
|
||||
{"Banana", 0.75},
|
||||
{"Cherry", 3.00},
|
||||
}
|
||||
|
||||
// Sort by price using SortByKey
|
||||
poindexter.SortByKey(products, func(p Product) float64 {
|
||||
return p.Price
|
||||
})
|
||||
|
||||
for _, p := range products {
|
||||
fmt.Printf("%s: $%.2f\n", p.Name, p.Price)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Check out the [API Reference](api.md) for detailed documentation
|
||||
- Read about the [License](license.md)
|
||||
49
docs/index.md
Normal file
49
docs/index.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Poindexter
|
||||
|
||||
Welcome to the Poindexter Go library documentation!
|
||||
|
||||
## Overview
|
||||
|
||||
Poindexter is a Go library package licensed under EUPL-1.2.
|
||||
|
||||
## Features
|
||||
|
||||
- Simple and easy to use
|
||||
- Comprehensive sorting utilities with custom comparators
|
||||
- Generic sorting functions with type safety
|
||||
- Binary search capabilities
|
||||
- Well-documented API
|
||||
- Comprehensive test coverage
|
||||
- Cross-platform support
|
||||
|
||||
## Quick Start
|
||||
|
||||
Install the library:
|
||||
|
||||
```bash
|
||||
go get github.com/Snider/Poindexter
|
||||
```
|
||||
|
||||
Use it in your code:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Snider/Poindexter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(poindexter.Hello("World"))
|
||||
fmt.Println("Version:", poindexter.Version())
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the European Union Public Licence v1.2 (EUPL-1.2).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
32
docs/license.md
Normal file
32
docs/license.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# License
|
||||
|
||||
This project is licensed under the **European Union Public Licence v1.2 (EUPL-1.2)**.
|
||||
|
||||
## About EUPL-1.2
|
||||
|
||||
The European Union Public Licence (EUPL) is a copyleft free/open source software license created on the initiative of and approved by the European Commission.
|
||||
|
||||
## Key Points
|
||||
|
||||
- **Open Source**: The EUPL is an OSI-approved open source license
|
||||
- **Copyleft**: Derivative works must be distributed under the same or compatible license
|
||||
- **Multilingual**: The license is available in all official EU languages
|
||||
- **Compatible**: Compatible with other major open source licenses including GPL
|
||||
|
||||
## Full License Text
|
||||
|
||||
The complete license text can be found in the [LICENSE](https://github.com/Snider/Poindexter/blob/main/LICENSE) file in the repository.
|
||||
|
||||
## Using EUPL-1.2 Licensed Code
|
||||
|
||||
When using this library:
|
||||
|
||||
1. You must retain copyright and license notices
|
||||
2. You must state significant changes made to the code
|
||||
3. Derivative works must be licensed under EUPL-1.2 or a compatible license
|
||||
|
||||
## More Information
|
||||
|
||||
For more information about the EUPL, visit:
|
||||
- [Official EUPL Website](https://joinup.ec.europa.eu/collection/eupl)
|
||||
- [EUPL on Wikipedia](https://en.wikipedia.org/wiki/European_Union_Public_Licence)
|
||||
3
go.mod
Normal file
3
go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/Snider/Poindexter
|
||||
|
||||
go 1.24.9
|
||||
61
mkdocs.yml
Normal file
61
mkdocs.yml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
site_name: Poindexter
|
||||
site_description: Poindexter Go Library Documentation
|
||||
site_author: Snider
|
||||
repo_url: https://github.com/Snider/Poindexter
|
||||
repo_name: Snider/Poindexter
|
||||
edit_uri: edit/main/docs/
|
||||
|
||||
theme:
|
||||
name: material
|
||||
palette:
|
||||
# Palette toggle for light mode
|
||||
- scheme: default
|
||||
primary: indigo
|
||||
accent: indigo
|
||||
toggle:
|
||||
icon: material/brightness-7
|
||||
name: Switch to dark mode
|
||||
# Palette toggle for dark mode
|
||||
- scheme: slate
|
||||
primary: indigo
|
||||
accent: indigo
|
||||
toggle:
|
||||
icon: material/brightness-4
|
||||
name: Switch to light mode
|
||||
features:
|
||||
- navigation.tabs
|
||||
- navigation.sections
|
||||
- navigation.top
|
||||
- search.suggest
|
||||
- search.highlight
|
||||
- content.tabs.link
|
||||
- content.code.annotation
|
||||
- content.code.copy
|
||||
|
||||
plugins:
|
||||
- search
|
||||
|
||||
markdown_extensions:
|
||||
- pymdownx.highlight:
|
||||
anchor_linenums: true
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.snippets
|
||||
- pymdownx.superfences
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- admonition
|
||||
- pymdownx.details
|
||||
- pymdownx.arithmatex:
|
||||
generic: true
|
||||
- footnotes
|
||||
- pymdownx.mark
|
||||
- attr_list
|
||||
- md_in_html
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Getting Started: getting-started.md
|
||||
- API Reference: api.md
|
||||
- License: license.md
|
||||
|
||||
copyright: Copyright © 2025 Snider
|
||||
15
poindexter.go
Normal file
15
poindexter.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Package poindexter provides functionality for the Poindexter library.
|
||||
package poindexter
|
||||
|
||||
// Version returns the current version of the library.
|
||||
func Version() string {
|
||||
return "0.1.0"
|
||||
}
|
||||
|
||||
// Hello returns a greeting message.
|
||||
func Hello(name string) string {
|
||||
if name == "" {
|
||||
return "Hello, World!"
|
||||
}
|
||||
return "Hello, " + name + "!"
|
||||
}
|
||||
34
poindexter_test.go
Normal file
34
poindexter_test.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package poindexter
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
version := Version()
|
||||
if version == "" {
|
||||
t.Error("Version should not be empty")
|
||||
}
|
||||
if version != "0.1.0" {
|
||||
t.Errorf("Expected version 0.1.0, got %s", version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHello(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"empty name", "", "Hello, World!"},
|
||||
{"with name", "Poindexter", "Hello, Poindexter!"},
|
||||
{"another name", "Go", "Hello, Go!"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := Hello(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("Hello(%q) = %q, want %q", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
89
sort.go
Normal file
89
sort.go
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package poindexter
|
||||
|
||||
import "sort"
|
||||
|
||||
// SortInts sorts a slice of integers in ascending order in place.
|
||||
func SortInts(data []int) {
|
||||
sort.Ints(data)
|
||||
}
|
||||
|
||||
// SortIntsDescending sorts a slice of integers in descending order in place.
|
||||
func SortIntsDescending(data []int) {
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(data)))
|
||||
}
|
||||
|
||||
// SortStrings sorts a slice of strings in ascending order in place.
|
||||
func SortStrings(data []string) {
|
||||
sort.Strings(data)
|
||||
}
|
||||
|
||||
// SortStringsDescending sorts a slice of strings in descending order in place.
|
||||
func SortStringsDescending(data []string) {
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(data)))
|
||||
}
|
||||
|
||||
// SortFloat64s sorts a slice of float64 values in ascending order in place.
|
||||
func SortFloat64s(data []float64) {
|
||||
sort.Float64s(data)
|
||||
}
|
||||
|
||||
// SortFloat64sDescending sorts a slice of float64 values in descending order in place.
|
||||
func SortFloat64sDescending(data []float64) {
|
||||
sort.Sort(sort.Reverse(sort.Float64Slice(data)))
|
||||
}
|
||||
|
||||
// SortBy sorts a slice using a custom less function.
|
||||
// The less function should return true if data[i] should come before data[j].
|
||||
func SortBy[T any](data []T, less func(i, j int) bool) {
|
||||
sort.Slice(data, less)
|
||||
}
|
||||
|
||||
// SortByKey sorts a slice by extracting a comparable key from each element.
|
||||
// The key function should return a value that implements constraints.Ordered.
|
||||
func SortByKey[T any, K int | float64 | string](data []T, key func(T) K) {
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
return key(data[i]) < key(data[j])
|
||||
})
|
||||
}
|
||||
|
||||
// SortByKeyDescending sorts a slice by extracting a comparable key from each element in descending order.
|
||||
func SortByKeyDescending[T any, K int | float64 | string](data []T, key func(T) K) {
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
return key(data[i]) > key(data[j])
|
||||
})
|
||||
}
|
||||
|
||||
// IsSorted checks if a slice of integers is sorted in ascending order.
|
||||
func IsSorted(data []int) bool {
|
||||
return sort.IntsAreSorted(data)
|
||||
}
|
||||
|
||||
// IsSortedStrings checks if a slice of strings is sorted in ascending order.
|
||||
func IsSortedStrings(data []string) bool {
|
||||
return sort.StringsAreSorted(data)
|
||||
}
|
||||
|
||||
// IsSortedFloat64s checks if a slice of float64 values is sorted in ascending order.
|
||||
func IsSortedFloat64s(data []float64) bool {
|
||||
return sort.Float64sAreSorted(data)
|
||||
}
|
||||
|
||||
// BinarySearch performs a binary search on a sorted slice of integers.
|
||||
// Returns the index where target is found, or -1 if not found.
|
||||
func BinarySearch(data []int, target int) int {
|
||||
idx := sort.SearchInts(data, target)
|
||||
if idx < len(data) && data[idx] == target {
|
||||
return idx
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// BinarySearchStrings performs a binary search on a sorted slice of strings.
|
||||
// Returns the index where target is found, or -1 if not found.
|
||||
func BinarySearchStrings(data []string, target string) int {
|
||||
idx := sort.SearchStrings(data, target)
|
||||
if idx < len(data) && data[idx] == target {
|
||||
return idx
|
||||
}
|
||||
return -1
|
||||
}
|
||||
347
sort_test.go
Normal file
347
sort_test.go
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
package poindexter
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSortInts(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []int
|
||||
expected []int
|
||||
}{
|
||||
{"empty slice", []int{}, []int{}},
|
||||
{"single element", []int{5}, []int{5}},
|
||||
{"already sorted", []int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5}},
|
||||
{"reverse sorted", []int{5, 4, 3, 2, 1}, []int{1, 2, 3, 4, 5}},
|
||||
{"unsorted", []int{3, 1, 4, 1, 5, 9, 2, 6}, []int{1, 1, 2, 3, 4, 5, 6, 9}},
|
||||
{"with negatives", []int{-3, 5, -1, 0, 2}, []int{-3, -1, 0, 2, 5}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := make([]int, len(tt.input))
|
||||
copy(data, tt.input)
|
||||
SortInts(data)
|
||||
if !reflect.DeepEqual(data, tt.expected) {
|
||||
t.Errorf("SortInts(%v) = %v, want %v", tt.input, data, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortIntsDescending(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []int
|
||||
expected []int
|
||||
}{
|
||||
{"empty slice", []int{}, []int{}},
|
||||
{"single element", []int{5}, []int{5}},
|
||||
{"ascending order", []int{1, 2, 3, 4, 5}, []int{5, 4, 3, 2, 1}},
|
||||
{"unsorted", []int{3, 1, 4, 1, 5, 9, 2, 6}, []int{9, 6, 5, 4, 3, 2, 1, 1}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := make([]int, len(tt.input))
|
||||
copy(data, tt.input)
|
||||
SortIntsDescending(data)
|
||||
if !reflect.DeepEqual(data, tt.expected) {
|
||||
t.Errorf("SortIntsDescending(%v) = %v, want %v", tt.input, data, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortStrings(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []string
|
||||
expected []string
|
||||
}{
|
||||
{"empty slice", []string{}, []string{}},
|
||||
{"single element", []string{"hello"}, []string{"hello"}},
|
||||
{"already sorted", []string{"a", "b", "c"}, []string{"a", "b", "c"}},
|
||||
{"reverse sorted", []string{"z", "y", "x"}, []string{"x", "y", "z"}},
|
||||
{"unsorted", []string{"banana", "apple", "cherry", "date"}, []string{"apple", "banana", "cherry", "date"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := make([]string, len(tt.input))
|
||||
copy(data, tt.input)
|
||||
SortStrings(data)
|
||||
if !reflect.DeepEqual(data, tt.expected) {
|
||||
t.Errorf("SortStrings(%v) = %v, want %v", tt.input, data, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortStringsDescending(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []string
|
||||
expected []string
|
||||
}{
|
||||
{"empty slice", []string{}, []string{}},
|
||||
{"ascending order", []string{"a", "b", "c"}, []string{"c", "b", "a"}},
|
||||
{"unsorted", []string{"banana", "apple", "cherry"}, []string{"cherry", "banana", "apple"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := make([]string, len(tt.input))
|
||||
copy(data, tt.input)
|
||||
SortStringsDescending(data)
|
||||
if !reflect.DeepEqual(data, tt.expected) {
|
||||
t.Errorf("SortStringsDescending(%v) = %v, want %v", tt.input, data, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortFloat64s(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []float64
|
||||
expected []float64
|
||||
}{
|
||||
{"empty slice", []float64{}, []float64{}},
|
||||
{"single element", []float64{3.14}, []float64{3.14}},
|
||||
{"unsorted", []float64{3.14, 1.41, 2.71, 1.73}, []float64{1.41, 1.73, 2.71, 3.14}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := make([]float64, len(tt.input))
|
||||
copy(data, tt.input)
|
||||
SortFloat64s(data)
|
||||
if !reflect.DeepEqual(data, tt.expected) {
|
||||
t.Errorf("SortFloat64s(%v) = %v, want %v", tt.input, data, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortFloat64sDescending(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []float64
|
||||
expected []float64
|
||||
}{
|
||||
{"empty slice", []float64{}, []float64{}},
|
||||
{"unsorted", []float64{3.14, 1.41, 2.71}, []float64{3.14, 2.71, 1.41}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := make([]float64, len(tt.input))
|
||||
copy(data, tt.input)
|
||||
SortFloat64sDescending(data)
|
||||
if !reflect.DeepEqual(data, tt.expected) {
|
||||
t.Errorf("SortFloat64sDescending(%v) = %v, want %v", tt.input, data, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortBy(t *testing.T) {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{"Alice", 30},
|
||||
{"Bob", 25},
|
||||
{"Charlie", 35},
|
||||
}
|
||||
|
||||
// Sort by age
|
||||
SortBy(people, func(i, j int) bool {
|
||||
return people[i].Age < people[j].Age
|
||||
})
|
||||
|
||||
expected := []Person{
|
||||
{"Bob", 25},
|
||||
{"Alice", 30},
|
||||
{"Charlie", 35},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(people, expected) {
|
||||
t.Errorf("SortBy (by age) = %v, want %v", people, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortByKey(t *testing.T) {
|
||||
type Product struct {
|
||||
Name string
|
||||
Price float64
|
||||
}
|
||||
|
||||
products := []Product{
|
||||
{"Apple", 1.50},
|
||||
{"Banana", 0.75},
|
||||
{"Cherry", 3.00},
|
||||
}
|
||||
|
||||
// Sort by price
|
||||
SortByKey(products, func(p Product) float64 {
|
||||
return p.Price
|
||||
})
|
||||
|
||||
expected := []Product{
|
||||
{"Banana", 0.75},
|
||||
{"Apple", 1.50},
|
||||
{"Cherry", 3.00},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(products, expected) {
|
||||
t.Errorf("SortByKey (by price) = %v, want %v", products, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortByKeyDescending(t *testing.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Score int
|
||||
}
|
||||
|
||||
students := []Student{
|
||||
{"Alice", 85},
|
||||
{"Bob", 92},
|
||||
{"Charlie", 78},
|
||||
}
|
||||
|
||||
// Sort by score descending
|
||||
SortByKeyDescending(students, func(s Student) int {
|
||||
return s.Score
|
||||
})
|
||||
|
||||
expected := []Student{
|
||||
{"Bob", 92},
|
||||
{"Alice", 85},
|
||||
{"Charlie", 78},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(students, expected) {
|
||||
t.Errorf("SortByKeyDescending (by score) = %v, want %v", students, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsSorted(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []int
|
||||
expected bool
|
||||
}{
|
||||
{"empty slice", []int{}, true},
|
||||
{"single element", []int{5}, true},
|
||||
{"sorted ascending", []int{1, 2, 3, 4, 5}, true},
|
||||
{"not sorted", []int{1, 3, 2, 4}, false},
|
||||
{"sorted with duplicates", []int{1, 1, 2, 3}, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := IsSorted(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsSorted(%v) = %v, want %v", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsSortedStrings(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []string
|
||||
expected bool
|
||||
}{
|
||||
{"sorted", []string{"a", "b", "c"}, true},
|
||||
{"not sorted", []string{"b", "a", "c"}, false},
|
||||
{"empty", []string{}, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := IsSortedStrings(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsSortedStrings(%v) = %v, want %v", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsSortedFloat64s(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []float64
|
||||
expected bool
|
||||
}{
|
||||
{"sorted", []float64{1.1, 2.2, 3.3}, true},
|
||||
{"not sorted", []float64{2.2, 1.1, 3.3}, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := IsSortedFloat64s(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsSortedFloat64s(%v) = %v, want %v", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
data := []int{1, 3, 5, 7, 9, 11}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
target int
|
||||
expected int
|
||||
}{
|
||||
{"found at start", 1, 0},
|
||||
{"found in middle", 5, 2},
|
||||
{"found at end", 11, 5},
|
||||
{"not found", 4, -1},
|
||||
{"not found - too small", 0, -1},
|
||||
{"not found - too large", 12, -1},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := BinarySearch(data, tt.target)
|
||||
if result != tt.expected {
|
||||
t.Errorf("BinarySearch(%v, %d) = %d, want %d", data, tt.target, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinarySearchStrings(t *testing.T) {
|
||||
data := []string{"apple", "banana", "cherry", "date"}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
target string
|
||||
expected int
|
||||
}{
|
||||
{"found at start", "apple", 0},
|
||||
{"found in middle", "banana", 1},
|
||||
{"found at end", "date", 3},
|
||||
{"not found", "grape", -1},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := BinarySearchStrings(data, tt.target)
|
||||
if result != tt.expected {
|
||||
t.Errorf("BinarySearchStrings(%v, %q) = %d, want %d", data, tt.target, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue