Skip to content

feat: Add SetRandomSeed and ResetRandomSeed for reproducible random sequences#763

Open
ukpratik wants to merge 4 commits intosamber:masterfrom
ukpratik:enable_xrand_seeding
Open

feat: Add SetRandomSeed and ResetRandomSeed for reproducible random sequences#763
ukpratik wants to merge 4 commits intosamber:masterfrom
ukpratik:enable_xrand_seeding

Conversation

@ukpratik
Copy link

Summary

This PR adds the ability to seed the random number generator used by lo functions, enabling reproducible random sequences. This is particularly useful for testing scenarios where deterministic behavior is required.

Motivation

When writing tests that involve random operations (e.g., Shuffle, RandomString,), it's often necessary to have predictable, reproducible results. Without the ability to seed the RNG, tests can be flaky or require workarounds.

Let me know if you think any changes that I should do in this PR or ay guidance, feel free to push any minor changes if required.

Use case example:

func TestMyFunction(t *testing.T) { lo.SetRandomSeed(42) defer lo.ResetRandomSeed() result := lo.Shuffle([]int{1, 2, 3, 4, 5}) // result is now deterministic and testable } 

Changes

New Public API

Function Description
SetRandomSeed(seed int64) Sets a custom seed for reproducible random sequences. Pass negative value to reset.
ResetRandomSeed() Resets to default non-reproducible behavior. Equivalent to SetRandomSeed(-1).

Files Changed

  • rand.go - New public API functions with documentation
  • rand_test.go - Comprehensive unit tests
  • internal/xrand/ordered_go118.go - Implementation for Go < 1.22
  • internal/xrand/ordered_go122.go - Implementation for Go ≥ 1.22
  • benchmark/slice_benchmark_test.go - Added BenchmarkShuffle

Testing

✅ Unit tests added covering:

  • Reproducible RandomString with same seed
  • Reproducible Shuffle with same seed
  • Different seeds produce different results
  • Reset returns to non-reproducible behavior
  • Negative seed resets the generator
  • Sequential operations are reproducible

Benchmarks

No performance regression detected.

Benchmark comparison (10 runs each):

Benchmark Master This PR Delta
Shuffle/ints_10 53.25 ns/op 51.61 ns/op -3.1%
Shuffle/ints_100 562.3 ns/op 552.8 ns/op -1.7%
Shuffle/ints_1000 5302.7 ns/op 5244.2 ns/op -1.1%
Shuffle/strings_10 56.40 ns/op 55.48 ns/op -1.6%
Shuffle/strings_100 592.1 ns/op 582.2 ns/op -1.7%
Shuffle/strings_1000 5761.4 ns/op 5660.2 ns/op -1.8%

Memory allocations: 0 B/op (unchanged)

Full benchmark output

Benchmark report for New changes:

goos: darwin goarch: arm64 pkg: github.com/samber/lo/benchmark cpu: Apple M3 Pro BenchmarkShuffle/ints_10-12 22587003 51.00 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 23390805 51.18 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 23498809 50.90 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22789028 51.59 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22319403 51.44 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 23575425 51.85 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 23278596 51.74 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22671862 52.29 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 23499038 52.15 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 23092372 51.92 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2263501 540.2 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2184102 545.2 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2216710 543.3 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2226292 539.6 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2171559 555.0 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2184602 546.8 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2183511 559.8 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2185424 599.6 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2134866 551.2 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2213470 546.9 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 224572 5225 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 230365 5311 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 231375 5215 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 223750 5268 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 231848 5175 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 234406 5154 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 227397 5170 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 231559 5253 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 204169 5400 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 226399 5271 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21962853 56.10 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21594774 55.41 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21210640 54.14 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21646046 55.35 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 22075224 55.24 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 20959996 55.55 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21657358 55.29 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 20714103 55.77 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21098035 55.74 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21860427 56.18 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2073867 572.6 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2070502 577.2 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2076459 581.9 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2069491 591.5 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2068453 584.5 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2090576 583.8 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2044184 574.3 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2064208 577.3 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2074052 588.5 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2045121 590.1 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 213916 5655 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 210658 5652 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 207843 5599 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 214982 5676 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 212762 5520 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 216505 5645 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 208477 5695 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 213548 5698 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 210241 5761 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 213153 5701 ns/op 0 B/op 0 allocs/op PASS ok github.com/samber/lo/benchmark 86.578s 

Benchmark report for Existing Code:

goos: darwin goarch: arm64 pkg: github.com/samber/lo/benchmark cpu: Apple M3 Pro BenchmarkShuffle/ints_10-12 23117040 52.43 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 21367854 54.19 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22240017 52.63 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22324420 52.45 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22729209 55.41 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22683309 52.80 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 21332353 52.72 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22611945 52.63 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22675004 53.34 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_10-12 22727684 53.94 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 1710760 645.1 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2121478 568.5 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2189866 560.8 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2182418 556.0 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2220439 546.8 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2193193 552.3 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2206826 548.0 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2199376 547.4 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2122310 549.6 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_100-12 2040598 548.8 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 221943 5242 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 227637 5245 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 223983 5352 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 225892 5367 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 227742 5372 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 228727 5289 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 228960 5280 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 225776 5271 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 225370 5313 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/ints_1000-12 225027 5296 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 20862414 55.53 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21787744 55.69 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21429224 57.00 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21864560 56.72 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 20709277 56.75 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21250220 56.29 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21672694 57.04 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21475212 55.86 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21096628 56.44 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_10-12 21537717 56.70 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2044614 603.9 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2029402 589.8 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2049004 587.2 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2062402 590.4 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2037243 589.6 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2014292 599.2 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2042222 603.0 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2026527 588.2 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2031366 588.6 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_100-12 2047062 581.5 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 215865 5617 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 210469 5625 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 209134 5704 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 212107 5807 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 199274 6554 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 209646 5670 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 212428 5661 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 213615 5663 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 212457 5671 ns/op 0 B/op 0 allocs/op BenchmarkShuffle/strings_1000-12 212714 5642 ns/op 0 B/op 0 allocs/op PASS ok github.com/samber/lo/benchmark 87.179s 
@ukpratik
Copy link
Author

@samber please check my new implementation for adding seed in xrand for test, I have detailed information for the same in the description, let me know what do you think about this.
I have also added benchmark comparisons with master code along with complete benchmark report of master and feature branch.
I would be always grateful for your guidance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants