mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 09:18:27 -04:00
151 lines
5.2 KiB
C#
151 lines
5.2 KiB
C#
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<T>(this IEnumerable<T> data, char separator, Func<T, string> func = null)
|
|
{
|
|
if (func is null)
|
|
func = x => x?.ToString() ?? string.Empty;
|
|
|
|
return string.Join(separator, data.Select(func));
|
|
}
|
|
|
|
public static string JoinWith<T>(this IEnumerable<T> data, string separator, Func<T, string> func = null)
|
|
{
|
|
func ??= x => x?.ToString() ?? string.Empty;
|
|
|
|
return string.Join(separator, data.Select(func));
|
|
}
|
|
|
|
public static IEnumerable<T> Distinct<T, U>(this IEnumerable<T> data, Func<T, U> getKey) =>
|
|
data.GroupBy(x => getKey(x))
|
|
.Select(x => x.First());
|
|
|
|
/// <summary>
|
|
/// Randomize element order by performing the Fisher-Yates shuffle
|
|
/// </summary>
|
|
/// <typeparam name="T">Item type</typeparam>
|
|
/// <param name="items">Items to shuffle</param>
|
|
public static IReadOnlyList<T> Shuffle<T>(this IEnumerable<T> 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<T> ForEach<T>(this IEnumerable<T> elems, Action<T> exec)
|
|
{
|
|
var realElems = elems.ToList();
|
|
foreach (var elem in realElems)
|
|
{
|
|
exec(elem);
|
|
}
|
|
|
|
return realElems;
|
|
}
|
|
|
|
public static ConcurrentDictionary<TKey, TValue> ToConcurrent<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dict)
|
|
=> new ConcurrentDictionary<TKey, TValue>(dict);
|
|
|
|
public static IndexedCollection<T> ToIndexed<T>(this IEnumerable<T> enumerable)
|
|
where T : class, IIndexed
|
|
=> new IndexedCollection<T>(enumerable);
|
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
/// <summary>
|
|
/// Split the elements of a sequence into chunks of size at most <paramref name="size"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Every chunk except the last will be of size <paramref name="size"/>.
|
|
/// The last chunk will contain the remaining elements and may be of a smaller size.
|
|
/// </remarks>
|
|
/// <param name="source">
|
|
/// An <see cref="IEnumerable{T}"/> whose elements to chunk.
|
|
/// </param>
|
|
/// <param name="size">
|
|
/// Maximum size of each chunk.
|
|
/// </param>
|
|
/// <typeparam name="TSource">
|
|
/// The type of the elements of source.
|
|
/// </typeparam>
|
|
/// <returns>
|
|
/// An <see cref="IEnumerable{T}"/> that contains the elements the input sequence split into chunks of size <paramref name="size"/>.
|
|
/// </returns>
|
|
/// <exception cref="ArgumentNullException">
|
|
/// <paramref name="source"/> is null.
|
|
/// </exception>
|
|
/// <exception cref="ArgumentOutOfRangeException">
|
|
/// <paramref name="size"/> is below 1.
|
|
/// </exception>
|
|
public static IEnumerable<TSource[]> Chunk<TSource>(this IEnumerable<TSource> 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<TSource[]> ChunkIterator<TSource>(IEnumerable<TSource> source, int size)
|
|
{
|
|
using IEnumerator<TSource> 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<TData[]> WhenAll<TData>(this IEnumerable<Task<TData>> items)
|
|
=> Task.WhenAll(items);
|
|
}
|
|
} |