| File: System\Linq\Shuffle.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq\src\System.Linq.csproj (System.Linq) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; namespace System.Linq { public static partial class Enumerable { /// <summary>Shuffles the order of the elements of a sequence.</summary> /// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam> /// <param name="source">A sequence of values to shuffle.</param> /// <returns>A sequence whose elements correspond to those of the input sequence in randomized order.</returns> /// <remarks>Randomization is performed using a non-cryptographically-secure random number generator.</remarks> public static IEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source) { if (source is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (IsEmptyArray(source)) { return []; } return new ShuffleIterator<TSource>(source); } private sealed partial class ShuffleIterator<TSource> : Iterator<TSource> { private readonly IEnumerable<TSource> _source; private TSource[]? _buffer; public ShuffleIterator(IEnumerable<TSource> source) { Debug.Assert(source is not null); _source = source; } private protected override Iterator<TSource> Clone() => new ShuffleIterator<TSource>(_source); public override bool MoveNext() { int state = _state; Initialized: if (state > 1) { TSource[]? buffer = _buffer; Debug.Assert(buffer is not null); int i = state - 2; if ((uint)i < (uint)buffer.Length) { _current = buffer[i]; _state++; return true; } } else if (state == 1) { TSource[] buffer = _source.ToArray(); if (buffer.Length != 0) { Random.Shared.Shuffle(buffer); _buffer = buffer; _state = state = 2; goto Initialized; } } Dispose(); return false; } public override void Dispose() { _buffer = null; base.Dispose(); } } } }