-
Notifications
You must be signed in to change notification settings - Fork 0
slices: introduce SliceP() #148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds an exported generic function Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant SliceP
participant doP
participant Sort
Caller->>SliceP: SliceP(slice, p)
SliceP->>doP: doP(slice, p, less)
note right of doP `#DDEEFF`: validate inputs\n(empty or invalid p -> zero value)\ncompute index = round(p*(n-1))\nclamp index
doP->>Sort: sort slice in-place using less
Sort-->>doP: sorted slice
doP-->>SliceP: return element at index
SliceP-->>Caller: percentile element
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Here's the code health analysis summary for commits Analysis Summary
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
PR Compliance Guide 🔍(Compliance updated until commit 05ecaea)Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label Previous compliance checksCompliance check up to commit 102e4ce
|
||||||||||||||||||||||||||||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
slices_test.go (1)
610-642: Consider optimising struct field alignment.The test case structure is well-designed with proper generic typing and factory function. However, reordering fields could reduce memory usage from 72 to 48 bytes per instance.
Apply this diff to optimise field alignment:
type doPTestCase[T comparable] struct { - name string input []T less func(T, T) bool + name string p float64 expected T }Based on static analysis.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
README.md(1 hunks)slices.go(1 hunks)slices_test.go(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
slices.go (1)
constraints.go (1)
Ordered(39-41)
slices_test.go (2)
testing.go (5)
TestCase(249-252)T(22-33)AssertEqual(278-287)S(240-245)RunTestCases(260-267)slices.go (1)
SliceCopy(199-206)
🪛 GitHub Check: make (1.23)
slices_test.go
[failure] 661-661:
The line is 122 characters long, which exceeds the maximum of 120 characters. (lll)
[failure] 611-611:
fieldalignment: struct with 72 pointer bytes could be 48 (govet)
🪛 GitHub Check: make (1.25)
slices_test.go
[failure] 661-661:
The line is 122 characters long, which exceeds the maximum of 120 characters. (lll)
[failure] 611-611:
fieldalignment: struct with 72 pointer bytes could be 48 (govet)
🪛 golangci-lint (2.5.0)
slices_test.go
[error] 661-661: File is not properly formatted
(gofmt)
[error] 611-611: fieldalignment: struct with 72 pointer bytes could be 48
(govet)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (7)
slices_test.go (4)
21-21: LGTM!The compile-time interface check correctly verifies that
doPTestCase[int]implements theTestCaseinterface, ensuring type safety at build time.
644-693: Comprehensive test coverage with excellent edge case handling.The test suite thoroughly covers percentile calculations across multiple types and scenarios, including boundary conditions, unsorted inputs, and various distributions. The inline comments documenting the index calculation formula are particularly helpful.
695-713: Excellent coverage of additional data types.Testing with
float64andstringtypes ensures the generic implementation works correctly across different ordered types. The test cases appropriately verify minimum, median, and maximum percentiles.
715-745: Thorough edge case validation.The separate test functions for empty slices and invalid percentile values ensure robust error handling. The expectation that invalid inputs return zero values is clearly documented and verified.
README.md (1)
187-187: LGTM!The documentation clearly describes the new
SlicePfunction and follows the established pattern for documenting slice operations.slices.go (2)
279-294: Well-documented public API with clear usage example.The function signature is clean, documentation explains the in-place sorting behaviour, and the example demonstrates practical usage for performance metrics. The implementation correctly delegates to the internal
doPhelper.
296-319: Solid percentile calculation with proper bounds handling.The implementation correctly handles edge cases (empty slices, invalid percentiles) and uses the nearest-rank percentile method with appropriate rounding. The in-place sorting optimises memory usage whilst the bounds clamping ensures index safety.
102e4ce to
f2e635b
Compare
PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
slices_test.go (1)
626-634: Consider clarifying the comment.The copy is created to prevent mutation of test data (since
SlicePsorts in-place), not specifically for testing unsorted data. The current implementation is correct.Consider this minor rewording:
- // Create a copy to test with unsorted data + // Create a copy since SliceP sorts in-place inputCopy := SliceCopy(tc.input)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
README.md(1 hunks)slices.go(1 hunks)slices_test.go(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- README.md
- slices.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-18T16:39:19.390Z
Learnt from: CR
Repo: darvaza-proxy/core PR: 0
File: AGENT.md:0-0
Timestamp: 2025-07-18T16:39:19.390Z
Learning: Applies to **/*.go : Max function length: 40 lines.
Applied to files:
slices_test.go
🧬 Code graph analysis (1)
slices_test.go (3)
testing.go (5)
TestCase(249-252)T(22-33)AssertEqual(278-287)S(240-245)RunTestCases(260-267)constraints.go (1)
Ordered(39-41)slices.go (2)
SliceCopy(199-206)SliceP(289-294)
🔇 Additional comments (4)
slices_test.go (4)
21-21: LGTM!The compile-time interface verification follows the established pattern in the file.
610-620: LGTM!The test case type is well-structured with appropriate generic constraints. The
nolintdirective for field alignment is reasonable given the generic type parameter.
636-644: LGTM!The factory function follows the established pattern and provides type-safe test case construction.
646-701: Excellent test coverage!The test suite comprehensively covers edge cases across multiple types (int, float64, string), including:
- Empty slices and single elements
- Various percentiles (P0, P25, P50, P75, P90, P95, P99, P100)
- Unsorted data, negative numbers, and duplicates
- Invalid percentile values (p < 0 or p > 1)
All test cases are mathematically correct and follow the established patterns in the codebase.
f2e635b to
8b3b0fe
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
slices_test.go (1)
646-701: Please keep TestSliceP within the 40-line capThis project limits Go functions to 40 lines, yet TestSliceP currently runs ~56 lines. Please split the integer/float/string suites into helper functions or subtests so the top-level stays within the agreed ceiling. Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
README.md(1 hunks)slices.go(1 hunks)slices_test.go(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- slices.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-18T16:39:19.390Z
Learnt from: CR
Repo: darvaza-proxy/core PR: 0
File: AGENT.md:0-0
Timestamp: 2025-07-18T16:39:19.390Z
Learning: Applies to **/*.go : Max function length: 40 lines.
Applied to files:
slices_test.go
🧬 Code graph analysis (1)
slices_test.go (3)
testing.go (5)
TestCase(249-252)T(22-33)AssertEqual(278-287)S(240-245)RunTestCases(260-267)constraints.go (1)
Ordered(39-41)slices.go (2)
SliceCopy(199-206)SliceP(289-294)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (go)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a fan for disabling govet in this test file, but ok. TestSliceP() should be made of separate t.Run("bar", runFooBar) instead of a monster TestFoo
|
You are right, I will rewrite the tests to not be forced to disable govet. |
returning the p-th percentile of a slice Signed-off-by: Nagy Károly Gábriel <k@jpi.io>
8b3b0fe to
38a1a6c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
README.md (1)
187-187: Consider enhancing the documentation for SliceP.The documentation is concise but could be more informative. Consider adding details about the valid range for
p(0.0 to 1.0), the in-place sorting behaviour, and what happens with invalid inputs.For example:
-* `SliceP[T](slice,p)` - return the p-th percentile of the slice +* `SliceP[T](slice,p)` - return the p-th percentile of the slice (p must be 0.0-1.0). Sorts the slice in-place. Returns zero value for empty slices or invalid p.slices.go (1)
279-294: Consider clarifying the in-place modification behaviour and parameter constraints.The implementation is correct, but the documentation could be clearer about two important aspects:
- The slice is modified in place, which might surprise users
- The valid range for
p(0.0 to 1.0) is mentioned in the internaldoPfunction but should be explicit hereConsider revising the documentation:
// SliceP returns the p-th percentile element from a slice. -// The slice will be sorted in place before calculating the percentile. +// The slice is sorted in place (modifying the original slice) before calculating the percentile. +// p must be between 0.0 (minimum) and 1.0 (maximum). Returns the zero value for +// empty slices or when p is outside the valid range. // This is commonly used for performance metrics and latency measurements // to identify outliers while excluding the worst values. -// If the slice is empty, returns the zero value of type T. // // Example: // // responseTimes := []int{100, 150, 120, 450, 89, 2000, 110, 130, 140, 160} -// p := SliceP(responseTimes,0.99) // Returns value at 99th percentile +// p99 := SliceP(responseTimes, 0.99) // Returns value at 99th percentile +// // Note: responseTimes is now sorted
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
README.md(1 hunks)slices.go(1 hunks)slices_test.go(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-18T16:39:19.390Z
Learnt from: CR
Repo: darvaza-proxy/core PR: 0
File: AGENT.md:0-0
Timestamp: 2025-07-18T16:39:19.390Z
Learning: Applies to **/*.go : Max function length: 40 lines.
Applied to files:
slices_test.go
🧬 Code graph analysis (2)
slices_test.go (2)
testing.go (5)
TestCase(249-252)T(22-33)AssertEqual(278-287)S(240-245)RunTestCases(260-267)slices.go (2)
SliceCopy(199-206)SliceP(289-294)
slices.go (1)
constraints.go (1)
Ordered(39-41)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (2)
slices.go (1)
296-316: Implementation logic is correct.The percentile calculation using the nearest-rank method with rounding is mathematically sound. The edge case handling (empty slices, invalid
pvalues, boundary clamping withmax()) is appropriate.slices_test.go (1)
612-733: Excellent test coverage.The test cases are comprehensive and well-structured:
- Properly implements the
TestCaseinterface pattern- Covers all critical scenarios: empty slices, single elements, common percentiles, edge cases (P0/P100), unsorted data, negative numbers, duplicates, and invalid inputs
- Tests across multiple types (int, float64, string)
- Uses
SliceCopyto avoid test pollution- Test expectations are mathematically correct
|
@coderabbitai @karasz Updated to address the review feedback: Documentation improvements:
Test structure (TESTING.md compliant):
|
|
Tip For best results, initiate chat on the files or code changes. @amery Thank you for the comprehensive updates! The improvements look great: ✅ Documentation - Adding the valid range (0.0-1.0), the in-place sorting warning, and edge case documentation will make the API much clearer for users. ✅ Test structure - The refactoring with factory functions and reducing These changes address the review feedback effectively. Nice work on keeping the codebase clean and well-documented! 🎉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
slices.go (2)
279-297: Document the percentile calculation method used.The documentation clearly explains the function's purpose and behaviour, but it doesn't specify which percentile calculation method is used (e.g., nearest rank, linear interpolation, etc.). Different statistical methods can produce different results, particularly with small datasets. Adding this detail would help users understand the exact behaviour and verify results against other implementations.
Consider adding a sentence to the documentation such as:
// SliceP returns the p-th percentile element from a slice. // The slice is sorted in place (modifying the original slice) before // calculating the percentile. p must be between 0.0 (minimum) and 1.0 -// (maximum). Returns the zero value for empty slices or when p is outside -// the valid range. +// (maximum). This implementation uses the nearest-rank method with rounding. +// Returns the zero value for empty slices or when p is outside the valid range.
316-316: Add an inline comment explaining the percentile index calculation.The formula
int(float64(n)*p+0.5)-1implements a nearest-rank percentile calculation with rounding, but this isn't immediately obvious. Adding a brief inline comment would improve code maintainability and help future readers understand the approach.Consider adding a comment:
doSliceSort(x, less) + // Calculate index using nearest-rank method: rank = round(n*p), then convert to 0-based index idx := max(int(float64(n)*p+0.5)-1, 0) return x[idx]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
README.md(1 hunks)slices.go(1 hunks)slices_test.go(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- README.md
- slices_test.go
🧰 Additional context used
🧬 Code graph analysis (1)
slices.go (1)
constraints.go (1)
Ordered(39-41)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (1)
slices.go (1)
309-312: Consider the implications of returning zero value for invalid percentile.The function silently returns the zero value when
p < 0orp > 1. Whilst this defensive approach avoids panics, it means callers cannot distinguish between "invalid input" and "percentile of empty slice". For a percentile value that represents a programmer error (invalidp), this might mask bugs.Consider whether this is the intended design, or if it would be better to panic for invalid
pvalues (programmer error) whilst keeping the zero-value return only for empty slices (valid edge case). This aligns with Go conventions where invalid inputs to pure functions often panic (e.g.,strings.Repeatwith negative count).
Enhance SliceP documentation to clarify behaviour and constraints: - Document valid range for p parameter (0.0-1.0). - Clarify in-place sorting behaviour with warning. - Document return value for invalid inputs. - Improve example code with better variable naming. Refactor SliceP tests to comply with TESTING.md requirements: - Extract test case arrays into factory functions. - Reduce TestSliceP from 56 lines to 5 lines. - Add slicePIntTestCases(), slicePFloatTestCases(), slicePStringTestCases() returning []TestCase. Addresses coderabbitai review comments about documentation clarity and function length compliance. Signed-off-by: Alejandro Mery <amery@apptly.co>
80b4dc7 to
05ecaea
Compare
User description
returning the p-th percentile of a slice
PR Type
Enhancement
Description
Introduces
SliceP()function for percentile calculationsImplements
doP()helper for generic percentile computationAdds comprehensive test coverage for integer, float, and string types
Updates documentation with new utility function
Diagram Walkthrough
File Walkthrough
slices.go
Implement percentile calculation functionsslices.go
SliceP[T Ordered]()public function to return p-th percentileelement
doP[T any]()helper function with in-place sorting andindex calculation
slices_test.go
Add comprehensive percentile function testsslices_test.go
slicePTestCase[T Ordered]test case structure with factoryfunction
TestSliceP()with 20+ test cases covering integers, floats,and strings
invalid inputs
duplicates
README.md
Document new SliceP utility functionREADME.md
SliceP[T](slice,p)to utilities documentation sectionSummary by CodeRabbit
New Features
Documentation
Tests