using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Threading.Tasks; using NadekoBot.Common.Collections; using NadekoBot.Core.Services.Database.Models; namespace NadekoBot.Extensions { public static class IEnumerableExtensions { public static string JoinWith(this IEnumerable data, char separator, Func func = null) { if (func is null) func = x => x?.ToString() ?? string.Empty; return string.Join(separator, data.Select(func)); } public static string JoinWith(this IEnumerable data, string separator, Func func = null) { func ??= x => x?.ToString() ?? string.Empty; return string.Join(separator, data.Select(func)); } public static IEnumerable Distinct(this IEnumerable data, Func getKey) => data.GroupBy(x => getKey(x)) .Select(x => x.First()); /// /// Randomize element order by performing the Fisher-Yates shuffle /// /// Item type /// Items to shuffle public static IReadOnlyList Shuffle(this IEnumerable items) { using var provider = RandomNumberGenerator.Create(); var list = items.ToList(); var n = list.Count; while (n > 1) { var box = new byte[(n / Byte.MaxValue) + 1]; int boxSum; do { provider.GetBytes(box); boxSum = box.Sum(b => b); } while (!(boxSum < n * ((Byte.MaxValue * box.Length) / n))); var k = (boxSum % n); n--; var value = list[k]; list[k] = list[n]; list[n] = value; } return list; } public static IEnumerable ForEach(this IEnumerable elems, Action exec) { var realElems = elems.ToList(); foreach (var elem in realElems) { exec(elem); } return realElems; } public static ConcurrentDictionary ToConcurrent(this IEnumerable> dict) => new ConcurrentDictionary(dict); public static IndexedCollection ToIndexed(this IEnumerable enumerable) where T : class, IIndexed => new IndexedCollection(enumerable); // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. /// /// Split the elements of a sequence into chunks of size at most . /// /// /// Every chunk except the last will be of size . /// The last chunk will contain the remaining elements and may be of a smaller size. /// /// /// An whose elements to chunk. /// /// /// Maximum size of each chunk. /// /// /// The type of the elements of source. /// /// /// An that contains the elements the input sequence split into chunks of size . /// /// /// is null. /// /// /// is below 1. /// public static IEnumerable Chunk(this IEnumerable source, int size) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (size < 1) { throw new ArgumentOutOfRangeException(nameof(size)); } return ChunkIterator(source, size); } private static IEnumerable ChunkIterator(IEnumerable source, int size) { using IEnumerator e = source.GetEnumerator(); while (e.MoveNext()) { TSource[] chunk = new TSource[size]; chunk[0] = e.Current; for (int i = 1; i < size; i++) { if (!e.MoveNext()) { Array.Resize(ref chunk, i); yield return chunk; yield break; } chunk[i] = e.Current; } yield return chunk; } } public static Task WhenAll(this IEnumerable> items) => Task.WhenAll(items); } }