using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Developpez.Dotnet.Properties; namespace Developpez.Dotnet.Collections { /// /// Fournit des méthodes d'extension pour la manipulation de tableaux /// public static class ArrayExtensions { #region Jagged and multidimensional arrays /// /// Renvoie une séquence contenant les lignes d'un tableau bidimensionnel. /// /// Type des éléments du tableau /// Tableau bidimensionnel dont on veut obtenir les lignes. /// Une séquence contenant les lignes du tableau public static IEnumerable GetRows(this T[,] array) { array.CheckArgumentNull("array"); return array.GetRowsImpl(); } private static IEnumerable GetRowsImpl(this T[,] array) { int rows = array.GetLength(0); int columns = array.GetLength(1); for (int i = 0; i < rows; i++) { T[] row = new T[columns]; for (int j = 0; j < columns; j++) { row[j] = array[i, j]; } yield return row; } } /// /// Renvoie un tableau en escalier avec le même contenu que le tableau bidimensionnel spécifié. /// /// Type des éléments du tableau /// Tableau bidimensionnel à convertir /// Un tableau en escalier avec le même contenu que le tableau bidimensionnel spécifié. public static T[][] ToJaggedArray(this T[,] array) { return array.GetRows().ToArray(); } /// /// Renvoie un tableau bidimensionnel avec le même contenu que le tableau en escalier spécifié. /// /// Type des éléments du tableau /// Tableau en escalier à convertir. /// Un tableau bidimensionnel avec le même contenu que le tableau en escalier spécifié. /// Le nombre de colonnes est déterminé en recherchant la plus longue ligne du tableau en escalier. /// Pour de meilleures performances, si vous savez que toutes les lignes ont la même longueur, utilisez la /// surcharge prenant un paramètre bool useFirstLineLength. public static T[,] ToBidimensionalArray(this T[][] jaggedArray) { return jaggedArray.ToBidimensionalArray(false); } /// /// Renvoie un tableau bidimensionnel avec le même contenu que le tableau en escalier spécifié. /// /// Type des éléments du tableau /// Tableau en escalier à convertir. /// true pour utiliser la longueur de la première ligne comme nombre de colonnes, false pour rechercher la ligne la plus longue. /// Un tableau bidimensionnel avec le même contenu que le tableau en escalier spécifié. /// Si useFirstLineLength vaut false, le nombre de colonnes est déterminé en recherchant la plus longue ligne /// du tableau en escalier. Pour de meilleures performances, si vous savez que toutes les lignes ont la même longueur, passez true /// pour le paramètre useFirstLineLength (une exception sera alors levée si une ligne est plus longue que la première). public static T[,] ToBidimensionalArray(this T[][] jaggedArray, bool useFirstLineLength) { jaggedArray.CheckArgumentNull("jaggedArray"); int rows = jaggedArray.Length; int columns; if (useFirstLineLength && jaggedArray.Length != 0) columns = jaggedArray[0].Length; else columns = jaggedArray.Select(row => row.Length).DefaultIfEmpty().Max(); T[,] array = new T[rows, columns]; for (int i = 0; i < rows; i++) { T[] row = jaggedArray[i]; int cols = row.Length; for (int j = 0; j < cols; j++) { array[i, j] = row[j]; } } return array; } #endregion #region ArraySegment related methods /// /// Renvoie le segment demandé d'un tableau /// /// Type des éléments du tableau /// Tableau dont on veut obtenir un segment /// Index de début du segment /// Nombre d'éléments dans le segment /// Le segment demandé du tableau public static ArraySegment GetSegment(this T[] array, int from, int count) { return new ArraySegment(array, from, count); } /// /// Renvoie un segment d'un tableau à partir de la position spécifiée /// /// Type des éléments du tableau /// Tableau dont on veut obtenir un segment /// Index de début du segment /// Le segment de tableau qui commence à la position spécifiée public static ArraySegment GetSegment(this T[] array, int from) { return GetSegment(array, from, array.Length - from); } /// /// Renvoie un segment de tableau représentant la totalité du tableau /// /// Type des éléments du tableau /// Tableau dont on veut obtenir un segment /// Un segment représentant la totalité du tableau public static ArraySegment GetSegment(this T[] array) { return new ArraySegment(array); } /// /// Renvoie un nouveau tableau à partir d'un segment de tableau /// /// Type des éléments du tableau /// Segment de tableau à partir duquel est créé le nouveau tableau /// Un tableau contenant tous les éléments du segment d'origine public static T[] ToArray(this ArraySegment arraySegment) { T[] array = new T[arraySegment.Count]; Array.Copy(arraySegment.Array, arraySegment.Offset, array, 0, arraySegment.Count); return array; } /// /// Renvoie une séquence qui énumère les éléments d'un segment de tableau /// /// Type des éléments du tableau /// Segment de tableau à énumérer /// Une séquence correspondant aux éléments du segment de tableau public static IEnumerable AsEnumerable(this ArraySegment arraySegment) { return arraySegment.Array.Skip(arraySegment.Offset).Take(arraySegment.Count); } /// /// Renvoie un wrapper pour un . /// /// Type des éléments du segment de tableau /// Segment de tableau pour lequel on veut obtenir un wrapper /// Un wrapper pour le segment de tableau public static IList AsList(this ArraySegment arraySegment) { return new ArraySegmentList(arraySegment); } private class ArraySegmentList : IList { private readonly ArraySegment _segment; public ArraySegmentList(ArraySegment segment) { _segment = segment; } #region Implementation of IEnumerable public IEnumerator GetEnumerator() { for (int i = 0; i < Count; i++) { yield return this[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region Implementation of ICollection public void Add(T item) { throw FixedLengthException(); } public void Clear() { throw FixedLengthException(); } public bool Contains(T item) { return this.AsEnumerable().Contains(item); } public void CopyTo(T[] array, int arrayIndex) { Array.Copy(_segment.Array, _segment.Offset, array, arrayIndex, _segment.Count); } public bool Remove(T item) { throw FixedLengthException(); } public int Count { get { return _segment.Count; } } public bool IsReadOnly { get { return false; } } #endregion #region Implementation of IList public int IndexOf(T item) { int arrayIndex = Array.IndexOf(_segment.Array, item, _segment.Offset, _segment.Count); if (arrayIndex != -1) return arrayIndex - _segment.Offset; return -1; } public void Insert(int index, T item) { throw FixedLengthException(); } public void RemoveAt(int index) { throw FixedLengthException(); } public T this[int index] { get { return _segment.Array[index + _segment.Offset]; } set { _segment.Array[index + _segment.Offset] = value; } } #endregion private Exception FixedLengthException() { return new InvalidOperationException(ExceptionMessages.CollectionFixedSize); } } #endregion #region ShiftLeft, ShiftRight /// /// Décale les éléments d'un tableau d'une position vers la gauche, /// en remplaçant le dernier élément par la valeur par défaut du type /// des éléments du tableau. Cette méthode ne modifie pas le tableau d'origine /// mais renvoie un nouveau tableau. /// /// Type des éléments du tableau /// Tableau à décaler /// Une copie décalée du tableau d'origine public static T[] ShiftLeft(this T[] array) { return array.ShiftLeft(default(T)); } /// /// Décale les éléments d'un tableau d'une position vers la gauche, /// en remplaçant le dernier élément par la valeur spécifiée. /// Cette méthode ne modifie pas le tableau d'origine mais renvoie un /// nouveau tableau. /// /// Type des éléments du tableau /// Tableau à décaler /// Valeur à insérer à la fin du tableau /// Une copie décalée du tableau d'origine public static T[] ShiftLeft(this T[] array, T value) { T[] newArray = new T[array.Length]; Array.Copy(array, 1, newArray, 0, array.Length - 1); newArray[array.Length - 1] = value; return newArray; } /// /// Décale les éléments d'un tableau d'une position vers la droite, /// en remplaçant le premier élément par la valeur par défaut du type /// des éléments du tableau. Cette méthode ne modifie pas le tableau d'origine /// mais renvoie un nouveau tableau. /// /// Type des éléments du tableau /// Tableau à décaler /// Une copie décalée du tableau d'origine public static T[] ShiftRight(this T[] array) { return array.ShiftRight(default(T)); } /// /// Décale les éléments d'un tableau d'une position vers la droite, /// en remplaçant le premier élément par la valeur spécifiée. /// Cette méthode ne modifie pas le tableau d'origine mais renvoie un /// nouveau tableau. /// /// Type des éléments du tableau /// Tableau à décaler /// Valeur à insérer au début du tableau /// Une copie décalée du tableau d'origine public static T[] ShiftRight(this T[] array, T value) { T[] newArray = new T[array.Length]; Array.Copy(array, 0, newArray, 1, array.Length - 1); newArray[0] = value; return newArray; } #endregion #region RotateLeft, RotateRight /// /// Effectue une rotation d'un tableau d'une position vers la gauche. /// Cette méthode ne modifie pas le tableau d'origine mais renvoie un /// nouveau tableau. /// /// Type des éléments du tableau /// Tableau sur lequel effectuer une rotation /// Une copie du tableau d'origine sur laquelle une rotation a été effectuée public static T[] RotateLeft(this T[] array) { return array.ShiftLeft(array.First()); } /// /// Effectue une rotation d'un tableau d'une position vers la droite. /// Cette méthode ne modifie pas le tableau d'origine mais renvoie un /// nouveau tableau. /// /// Type des éléments du tableau /// Tableau sur lequel effectuer une rotation /// Une copie du tableau d'origine sur laquelle une rotation a été effectuée public static T[] RotateRight(this T[] array) { return array.ShiftRight(array.Last()); } #endregion } }