using System;
using System.Collections.Generic;
using System.Linq;
using Developpez.Dotnet.Properties;
using JetBrains.Annotations;
namespace Developpez.Dotnet.Collections
{
public static partial class EnumerableExtensions
{
#region BinarySearch and related methods
///
/// Effectue une recherche binaire sur une liste triée pour trouver un élément selon
/// la valeur d'une de ses propriétés. La liste doit être triée selon cette propriété.
///
/// Type des éléments de la collection
/// Type de la clé de recherche
/// Liste dans laquelle rechercher l'élément
/// Fonction permettant d'obtenir la clé de recherche
/// Valeur de la clé recherchée
/// Le premier élément correspondant, s'il existe. Sinon, lève une InvalidOperationException.
public static T BinarySearch(
[NotNull] this IList list,
[NotNull] Func keySelector,
TKey key)
where TKey : IComparable
{
T result;
if (list.TryBinarySearch(keySelector, key, out result))
return result;
throw new InvalidOperationException(ExceptionMessages.NoMatchingItemInList);
}
///
/// Effectue une recherche binaire sur une liste triée pour trouver un élément selon
/// la valeur d'une de ses propriétés. La liste doit être triée selon cette propriété.
/// Si aucun élément correspondant n'est trouvé, une valeur par défaut est renvoyée.
///
/// Type des éléments de la collection
/// Type de la clé de recherche
/// Liste dans laquelle rechercher l'élément
/// Fonction permettant d'obtenir la clé de recherche
/// Valeur de la clé recherchée
/// Le premier élément correspondant, s'il existe. Sinon, la valeur par défaut du type T.
public static T BinarySearchOrDefault(
[NotNull] this IList list,
[NotNull] Func keySelector,
TKey key)
where TKey : IComparable
{
return list.BinarySearchOrDefault(keySelector, key, default(T));
}
///
/// Effectue une recherche binaire sur une liste triée pour trouver un élément selon
/// la valeur d'une de ses propriétés. La liste doit être triée selon cette propriété.
/// Si aucun élément correspondant n'est trouvé, la valeur par défaut spécifiée est renvoyée.
///
/// Type des éléments de la collection
/// Type de la clé de recherche
/// Liste dans laquelle rechercher l'élément
/// Fonction permettant d'obtenir la clé de recherche
/// Valeur de la clé recherchée
/// La valeur par défaut à renvoyer si aucun élément correspondant n'est trouvé
/// Le premier élément correspondant, s'il existe. Sinon, la valeur par défaut spécifiée.
public static T BinarySearchOrDefault(
[NotNull] this IList list,
[NotNull] Func keySelector,
TKey key,
T defaultValue)
where TKey : IComparable
{
T result;
if (list.TryBinarySearch(keySelector, key, out result))
return result;
return defaultValue;
}
///
/// Effectue une recherche binaire sur une liste triée pour tenter de trouver un élément
/// selon la valeur d'une de ses propriétés. La liste doit être triée selon cette propriété.
///
/// Type des éléments de la collection
/// Type de la clé de recherche
/// Liste dans laquelle rechercher l'élément
/// Fonction permettant d'obtenir la clé de recherche
/// Valeur de la clé recherchée
/// Paramètre de sortie qui prend la valeur du premier élément trouvé.
/// true si un élément correspondant est trouvé. Sinon, false.
public static bool TryBinarySearch(
[NotNull] this IList list,
[NotNull] Func keySelector,
TKey key,
out T result)
where TKey : IComparable
{
list.CheckArgumentNull("list");
keySelector.CheckArgumentNull("keySelector");
result = default(T);
int min = 0;
int max = list.Count;
while (min < max)
{
int mid = (max + min) / 2;
T midItem = list[mid];
TKey midKey = keySelector(midItem);
int comp = midKey.CompareTo(key);
if (comp < 0)
{
min = mid + 1;
}
else if (comp > 0)
{
max = mid - 1;
}
else
{
result = midItem;
return true;
}
}
if (min == max &&
keySelector(list[min]).CompareTo(key) == 0)
{
result = list[min];
return true;
}
return false;
}
#endregion
#region QuickSort
///
/// Trie la liste en utilisant l'algorithme Quicksort
///
/// Type des éléments de la liste
/// Liste à trier
public static void QuickSort([NotNull] this IList list)
{
Comparison comparison = Comparer.Default.ToComparison();
QuickSort(list, comparison);
}
///
/// Trie la liste selon la clé spécifiée en utilisant l'algorithme Quicksort
///
/// Type des éléments de la liste
/// Type de la clé de tri
/// Liste à trier
/// Fonction qui renvoie la clé de tri
public static void QuickSortBy(
[NotNull] this IList list,
[NotNull] Func keySelector)
{
keySelector.CheckArgumentNull("keySelector");
Comparison keyComparison = Comparer.Default.ToComparison();
Comparison comparison = (a, b) => keyComparison(keySelector(a), keySelector(b));
QuickSort(list, comparison);
}
///
/// Trie la liste en utilisant l'algorithme Quicksort, avec le comparateur spécifié
///
/// Type des éléments de la liste
/// Liste à trier
/// Comparateur à utiliser
public static void QuickSort(
[NotNull] this IList list,
[NotNull] IComparer comparer)
{
comparer.CheckArgumentNull("comparer");
QuickSort(list, comparer.ToComparison());
}
///
/// Trie la liste en utilisant l'algorithme Quicksort, avec la fonction de comparaison spécifiée
///
/// Type des éléments de la liste
/// Liste à trier
/// Fonction de comparaison à utiliser
public static void QuickSort(
[NotNull] this IList list,
[NotNull] Comparison comparison)
{
list.CheckArgumentNull("list");
QuickSort(list, 0, list.Count - 1, comparison);
}
private static void QuickSort(IList list, int left, int right, Comparison comparison)
{
if (right > left)
{
int pivot = left;
QuickSortPartition(list, left, right, ref pivot, comparison);
QuickSort(list, left, pivot - 1, comparison);
QuickSort(list, pivot + 1, right, comparison);
}
}
private static void QuickSortPartition(IList list, int left, int right, ref int pivot, Comparison comparison)
{
T pivotValue = list[pivot];
list.Swap(pivot, right);
int tmpIndex = left;
for (int i = left; i < right; i++)
{
if (comparison(list[i], pivotValue) <= 0)
{
list.Swap(i, tmpIndex);
tmpIndex++;
}
}
list.Swap(tmpIndex, right);
pivot = tmpIndex;
}
#endregion
#region AddRange
///
/// Ajoute plusieurs éléments à une collection
///
/// Type des éléments de la collection
/// Collection à laquelle ajouter des éléments
/// Eléments à ajouter
public static void AddRange(
[NotNull] this ICollection collection,
[NotNull] IEnumerable items)
{
collection.CheckArgumentNull("collection");
items.CheckArgumentNull("items");
foreach (var item in items)
{
collection.Add(item);
}
}
#endregion
#region RemoveRange
///
/// Retire d'une liste le nombre d'éléments spécifié à partir de la position spécifiée
///
/// Type des éléments de la liste
/// Liste de laquelle on retire des éléments
/// Position à partir de laquelle on retire des éléments
/// Nombre d'éléments à retirer
public static void RemoveRange(
[NotNull] this IList list,
int index,
int count)
{
list.CheckArgumentNull("list");
index.CheckArgumentOutOfRange("index", 0, list.Count - 1);
count.CheckArgumentOutOfRange("count", 0, list.Count - index);
for (int i = 0; i < count; i++)
{
list.RemoveAt(index);
}
}
#endregion
#region InsertRange
///
/// Insère les éléments spécifiés dans une liste à partir de la position spécifiée
///
/// Type des éléments de la liste
/// Liste dans laquelle on insère les éléments
/// Position à partir de laquelle insérer les éléments
/// Éléments à insérer
public static void InsertRange(
[NotNull] this IList list,
int index,
[NotNull] IEnumerable items)
{
list.CheckArgumentNull("list");
index.CheckArgumentOutOfRange("index", 0, list.Count);
items.CheckArgumentNull("items");
foreach (var item in items)
{
list.Insert(index++, item);
}
}
#endregion
#region RemoveAll
///
/// Retire d'une collection tous les éléments qui vérifient le prédicat spécifié
///
/// Type des éléments de la liste
/// Collection de laquelle on retire des éléments
/// Prédicat qui indique si un élément doit être retiré
/// Le nombre d'éléments retirés
public static int RemoveAll(
[NotNull] this ICollection collection,
[NotNull] Func predicate)
{
collection.CheckArgumentNull("collection");
predicate.CheckArgumentNull("predicate");
var toRemove = collection.Where(predicate).ToList();
foreach (var item in toRemove)
{
collection.Remove(item);
}
return toRemove.Count;
}
#endregion
#region Shuffle
///
/// Mélange une liste.
///
/// Type des éléments de la séquence
/// La liste à mélanger
/// Cette méthode utilise l'algorithme de Fisher–Yates (http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
///
public static void Shuffle([NotNull] this IList list)
{
list.Shuffle(new Random());
}
///
/// Mélange une liste en spécifiant le générateur de nombres aléatoires à utiliser.
///
/// Type des éléments de la séquence
/// La liste à mélanger
/// Le générateur de nombres aléatoires à utiliser
/// Cette méthode utilise l'algorithme de Fisher–Yates (http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
///
public static void Shuffle(
[NotNull] this IList list,
[NotNull] Random rnd)
{
list.CheckArgumentNull("list");
rnd.CheckArgumentNull("rnd");
for (int i = list.Count - 1; i > 0; i--)
{
int swapIndex = rnd.Next(i + 1);
list.Swap(i, swapIndex);
}
}
#endregion
#region Swap
///
/// Permute deux éléments d'une liste
///
/// Type des éléments de la liste
/// La liste contenant les éléments à permuter
/// L'index du premier élément
/// L'index du second élément
public static void Swap(
[NotNull] this IList list,
int index1,
int index2)
{
list.CheckArgumentNull("list");
index1.CheckArgumentOutOfRange("index1", 0, list.Count - 1);
index1.CheckArgumentOutOfRange("index2", 0, list.Count - 1);
T tmp = list[index1];
list[index1] = list[index2];
list[index2] = tmp;
}
#endregion
#region ToHashSet
///
/// Crée un à partir d'un avec le comparateur par défaut.
///
/// Type des éléments de source
/// Séquence à partir de laquelle créer un
/// Un qui contient les éléments de la séquence d'entrée.
public static HashSet ToHashSet([NotNull] this IEnumerable source)
{
source.CheckArgumentNull("source");
return new HashSet(source);
}
///
/// Crée un à partir d'un avec le comparateur spécifié.
///
/// Type des éléments de source
/// Séquence à partir de laquelle créer un
/// Comparateur à utiliser pour comparer les éléments.
/// Un qui contient les éléments de la séquence d'entrée.
public static HashSet ToHashSet([NotNull] this IEnumerable source, IEqualityComparer comparer)
{
source.CheckArgumentNull("source");
return new HashSet(source, comparer);
}
#endregion
#region ToStack
///
/// Crée une à partir d'un .
///
/// Type des éléments de source
/// Séquence à partir de laquelle créer une
/// Une qui contient les éléments de la séquence d'entrée.
public static Stack ToStack([NotNull] this IEnumerable source)
{
source.CheckArgumentNull("source");
return new Stack(source);
}
#endregion
#region ToQueue
///
/// Crée une à partir d'un .
///
/// Type des éléments de source
/// Séquence à partir de laquelle créer une
/// Une qui contient les éléments de la séquence d'entrée.
public static Queue ToQueue([NotNull] this IEnumerable source)
{
source.CheckArgumentNull("source");
return new Queue(source);
}
#endregion
}
}