using System;
using System.Collections.Generic;
using System.Linq;
using Hazel;
// ReSharper disable ConvertIfStatementToReturnStatement
// ReSharper disable ForCanBeConvertedToForeach
namespace EHR;
public static class CollectionExtensions
{
///
/// Returns the key of a dictionary by its value
///
/// The to search
/// The used to search for the corresponding key
/// The type of the keys in the
/// The type of the values in the
///
/// The key of the that corresponds to the given , or the
/// default value of if the is not found in the
///
///
public static TKey GetKeyByValue(this Dictionary dictionary, TValue value)
{
foreach (KeyValuePair pair in dictionary)
{
if (pair.Value.Equals(value))
return pair.Key;
}
return default(TKey);
}
///
/// Sets the value for all existing keys in a dictionary to a specific value
///
///
///
///
///
public static void SetAllValues(this Dictionary dictionary, TValue value)
{
foreach (TKey key in dictionary.Keys.ToArray()) dictionary[key] = value;
}
///
/// Adjusts the value for all existing keys in a dictionary
///
/// The dictionary to adjust the values of
/// The function to adjust the values with
///
///
public static void AdjustAllValues(this Dictionary dictionary, Func adjust)
{
foreach (TKey key in dictionary.Keys.ToArray()) dictionary[key] = adjust(dictionary[key]);
}
///
/// Returns a random element from a collection
///
/// The collection
/// The type of the collection
///
/// A random element from the collection, or the default value of if the collection is
/// empty
///
public static T RandomElement(this IList collection)
{
if (collection.Count == 0) return default(T);
return collection[IRandom.Instance.Next(collection.Count)];
}
///
/// Returns a random element from a collection
///
/// The collection
/// The type of the collection
///
/// A random element from the collection, or the default value of if the collection is
/// empty
///
public static T RandomElement(this IEnumerable collection)
{
if (collection is IList list) return list.RandomElement();
return collection.ToList().RandomElement();
}
///
/// Combines multiple collections into a single collection
///
/// The collection to start with
/// The other collections to add to
/// The type of the elements in the collections to combine
///
/// A collection containing all elements of and all
///
///
public static IEnumerable CombineWith(this IEnumerable firstCollection, params IEnumerable[] collections)
{
return firstCollection.Concat(collections.Flatten());
}
///
/// Executes an action for each element in a collection
///
/// The collection to iterate over
/// The action to execute for each element
/// The type of the elements in the collection
public static void Do(this IEnumerable collection, Action action)
{
if (collection is List list)
{
for (var i = 0; i < list.Count; i++) action(list[i]);
return;
}
foreach (T element in collection) action(element);
}
///
/// Executes an action for each element in a collection if the predicate is true
///
/// The collection to iterate over
/// Whether to use a fast loop or linq
/// The predicate to check for each element
/// The action to execute for each element that satisfies the predicate
/// The type of the elements in the collection
public static void DoIf(this IEnumerable collection, Func predicate, Action action, bool fast = true)
{
if (fast)
{
if (collection is List list)
{
for (var i = 0; i < list.Count; i++)
{
T element = list[i];
if (predicate(element)) action(element);
}
return;
}
foreach (T element in collection)
{
if (predicate(element))
action(element);
}
return;
}
collection.Where(predicate).ToArray().Do(action);
}
///
/// Splits a collection into two collections based on a predicate
///
/// The collection to split
/// The predicate to split the collection by
/// The type of the elements in the collection
///
/// A tuple containing two collections: one with elements that satisfy the predicate, and one with elements that
/// do not
///
public static (List TrueList, List FalseList) Split(this IEnumerable collection, Func predicate)
{
var list1 = new List();
var list2 = new List();
foreach (T element in collection)
{
if (predicate(element))
list1.Add(element);
else
list2.Add(element);
}
return (list1, list2);
}
///
/// Adds a range of elements to a dictionary
///
/// The dictionary to add elements to
/// The dictionary containing the elements to add
///
/// Whether to override existing keys in the with the
/// same keys in the dictionary. If true, the same keys in the
/// will be overwritten with the values from the dictionary.
/// If false, the same keys in the will be kept and the values from the
/// dictionary will be ignored
///
/// The type of the keys in the dictionaries
/// The type of the values in the dictionaries
/// The with the elements from the dictionary added
public static Dictionary AddRange(this Dictionary dictionary, Dictionary other, bool overrideExistingKeys = true)
{
foreach ((TKey key, TValue value) in other)
{
if (overrideExistingKeys || !dictionary.ContainsKey(key))
dictionary[key] = value;
}
return dictionary;
}
///
/// Flattens a collection of collections into a single collection
///
/// The collection of collections to flatten
/// The type of the elements in the collections
/// A single collection containing all elements of the collections in
public static IEnumerable Flatten(this IEnumerable> collection)
{
return collection.SelectMany(x => x);
}
///
/// Determines whether a collection contains any elements that satisfy a predicate and returns the first element that
/// satisfies the predicate
///
/// The collection to search
/// The predicate to check for each element
///
/// The first element that satisfies the predicate, or the default value of
/// if no elements satisfy the predicate
///
/// The type of the elements in the collection
/// true if the collection contains any elements that satisfy the predicate, false otherwise
public static bool FindFirst(this IEnumerable collection, Func predicate, out T element)
{
if (collection is List list)
{
for (var i = 0; i < list.Count; i++)
{
T item = list[i];
if (predicate(item))
{
element = item;
return true;
}
}
element = default(T);
return false;
}
foreach (T item in collection)
{
if (predicate(item))
{
element = item;
return true;
}
}
element = default(T);
return false;
}
public static void NotifyPlayers(this IEnumerable players, string text, float time = 6f, bool overrideAll = false, bool log = true, bool setName = true)
{
var sender = CustomRpcSender.Create("NotifyPlayers", SendOption.Reliable);
var hasValue = false;
foreach (PlayerControl player in players)
{
sender.Notify(player, text, time, overrideAll, log, setName);
hasValue = true;
if (sender.stream.Length > 800)
{
sender.SendMessage();
sender = CustomRpcSender.Create("NotifyPlayers", SendOption.Reliable);
hasValue = false;
}
}
sender.SendMessage(dispose: !hasValue);
}
#region ToValidPlayers
///
/// Converts a collection of player IDs to a collection of instances
///
///
///
public static IEnumerable ToValidPlayers(this IEnumerable playerIds)
{
return playerIds.Select(Utils.GetPlayer).Where(x => x != null);
}
///
/// Converts a list of player IDs to a list of instances
///
///
///
public static List ToValidPlayers(this List playerIds)
{
return playerIds.ConvertAll(Utils.GetPlayer).FindAll(x => x != null);
}
#endregion
#region Without
///
/// Removes an element from a collection
///
/// The collection to remove the element from
/// The element to remove
/// The type of the elements in the collection
///
/// A collection containing all elements of except for
///
public static IEnumerable Without(this IEnumerable collection, T element)
{
return collection.Where(x => !x.Equals(element));
}
///
/// Removes an element from a collection
///
/// The collection to remove the element from
/// The element to remove
///
/// A collection containing all elements of except for
///
public static IEnumerable Without(this IEnumerable collection, PlayerControl element)
{
return collection.Where(x => x.PlayerId != element.PlayerId);
}
///
/// Removes an element from a collection
///
/// The collection to remove the element from
/// The element to remove
///
/// A collection containing all elements of except for
///
public static IEnumerable Without(this IEnumerable collection, PlainShipRoom element)
{
return collection.Where(x => x != element);
}
#endregion
#region Shuffle
///
/// Shuffles all elements in a collection randomly
///
/// The type of the collection
/// The collection to be shuffled
/// A new, shuffled collection as a
public static List Shuffle(this IEnumerable collection)
{
List list = collection.ToList();
int n = list.Count;
var r = IRandom.Instance;
while (n > 1)
{
n--;
int k = r.Next(n + 1);
(list[n], list[k]) = (list[k], list[n]);
}
return list;
}
///
/// Shuffles all elements in a collection randomly
///
/// The collection to be shuffled
/// The type of the collection
/// The same collection with its elements shuffled
public static List Shuffle(this List collection)
{
int n = collection.Count;
var r = IRandom.Instance;
while (n > 1)
{
n--;
int k = r.Next(n + 1);
(collection[n], collection[k]) = (collection[k], collection[n]);
}
return collection;
}
///
/// Shuffles all elements in an array randomly
///
/// The array to be shuffled
/// The type of the array
/// The same array with its elements shuffled
public static T[] Shuffle(this T[] collection)
{
int n = collection.Length;
var r = IRandom.Instance;
while (n > 1)
{
n--;
int k = r.Next(n + 1);
(collection[n], collection[k]) = (collection[k], collection[n]);
}
return collection;
}
#endregion
#region Partition
///
/// Partitions a collection into a specified number of parts
///
/// The collection to partition
/// The number of parts to partition the collection into
/// The type of the elements in the collection
/// A collection of collections, each containing a part of the original collection
public static IEnumerable> Partition(this IEnumerable collection, int parts)
{
List list = collection.ToList();
int length = list.Count;
if (parts <= 0 || length == 0) yield break;
if (parts > length) parts = length;
int size = length / parts;
int remainder = length % parts;
var index = 0;
for (var i = 0; i < parts; i++)
{
int partSize = size + (i < remainder ? 1 : 0);
yield return list.Skip(index).Take(partSize);
index += partSize;
}
}
///
/// Partitions a list into a specified number of parts
///
/// The list to partition
/// The number of parts to partition the list into
/// The type of the elements in the list
/// A list of lists, each containing a part of the original list
public static IEnumerable> Partition(this IList collection, int parts)
{
int length = collection.Count;
if (parts <= 0 || length == 0) yield break;
if (parts > length) parts = length;
int size = length / parts;
int remainder = length % parts;
var index = 0;
for (var i = 0; i < parts; i++)
{
int partSize = size + (i < remainder ? 1 : 0);
yield return collection.Skip(index).Take(partSize);
index += partSize;
}
}
#endregion
}
public static class Loop
{
public static void Times(int count, Action action)
{
for (var i = 0; i < count; i++) action(i);
}
}