remarks example cref c# python algorithm

example - params comments c#



C#equivalente a la rotaciĆ³n de una lista usando la operaciĆ³n de corte python (5)

Lo más parecido en C # sería usar los métodos de extensión Enumerable.Skip y Enumerable.Take . Podría usarlos para construir su nueva lista.

En python, puedo tomar una lista my_list y rotar los contenidos:

>>> my_list = list(range(10)) >>> my_list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> new_list = my_list[1:] + my_list[:1] >>> new_list [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

¿Cuál es el camino equivalente en C # para crear una nueva lista que está compuesta por dos segmentos de una lista C # existente? Sé que puedo generar por la fuerza bruta si es necesario.


Para rotar la matriz, haga a.Slice(1, null).Concat(a.Slice(null, 1)) .

Aquí está mi puñalada. a.Slice(step: -1) da una copia invertida como a[::-1] .

/// <summary> /// Slice an array as Python. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="array"></param> /// <param name="start">start index.</param> /// <param name="end">end index.</param> /// <param name="step">step</param> /// <returns></returns> /// <remarks> /// http://docs.python.org/2/tutorial/introduction.html#strings /// +---+---+---+---+---+ /// | H | e | l | p | A | /// +---+---+---+---+---+ /// 0 1 2 3 4 5 /// -6 -5 -4 -3 -2 -1 /// </remarks> public static IEnumerable<T> Slice<T>(this T[] array, int? start = null, int? end = null, int step = 1) { array.NullArgumentCheck("array"); // step if (step == 0) { // handle gracefully yield break; } // step > 0 int _start = 0; int _end = array.Length; // step < 0 if (step < 0) { _start = -1; _end = -array.Length - 1; } // inputs _start = start ?? _start; _end = end ?? _end; // get positive index for given index Func<int, int, int> toPositiveIndex = (int index, int length) => { return index >= 0 ? index : index + length; }; // start if (_start < -array.Length || _start >= array.Length) { yield break; } _start = toPositiveIndex(_start, array.Length); // end if (_end < -array.Length - 1) { yield break; } if (_end > array.Length) { _end = array.Length; } _end = toPositiveIndex(_end, array.Length); // slice if (step > 0) { // start, end if (_start > _end) { yield break; } for (int i = _start; i < _end; i += step) { yield return array[i]; } } else { // start, end if (_end > _start) { yield break; } for (int i = _start; i > _end; i += step) { yield return array[i]; } } }

pruebas nunit:

[Test] // normal cases [TestCase(3, 5, 1, 3, 4)] [TestCase(0, 5, 1, 0, 4)] [TestCase(3, null, 1, 3, 9)] [TestCase(0, null, 1, 0, 9)] [TestCase(null, null, 1, 0, 9)] [TestCase(0, 10, 1, 0, 9)] [TestCase(0, int.MaxValue, 1, 0, 9)] [TestCase(-1, null, 1, 9, 9)] [TestCase(-2, null, 1, 8, 9)] [TestCase(0, -2, 1, 0, 7)] // corner cases [TestCase(0, 0, 1, null, null)] [TestCase(3, 5, 2, 3, 3)] [TestCase(3, 6, 2, 3, 5)] [TestCase(100, int.MaxValue, 1, null, null)] [TestCase(int.MaxValue, 1, 1, null, null)] [TestCase(-11, int.MaxValue, 1, null, null)] [TestCase(-6, -5, 1, 4, 4)] [TestCase(-5, -6, 1, null, null)] [TestCase(-5, -5, 1, null, null)] [TestCase(0, -10, 1, null, null)] [TestCase(0, -11, 1, null, null)] [TestCase(null, null, 100, 0, 0)] // -ve step [TestCase(null, null, -1, 9, 0)] [TestCase(-7, -5, -1, null, null)] [TestCase(-5, -7, -1, 5, 4)] [TestCase(-5, -7, -2, 5, 5)] [TestCase(-7, null, -1, 3, 0)] public void Slice01(int? s, int? e, int i, int? first, int? last) { var a = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var slice = a.Slice(start: s, end: e, step: i).ToArray(); Print(slice); if (first.HasValue) { Assert.AreEqual(first, slice.First()); } if (last.HasValue) { Assert.AreEqual(last, slice.Last()); } }


Puede usar LINQ fácilmente para hacer esto:

// Create the list int[] my_list = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; IEnumerable<int> new_list = my_list.Skip(1).Concat(my_list.Take(1));

Incluso podría agregar esto como un método de extensión como ese:

public static IEnumerable<T> Slice<T>(this IEnumerable<T> e, int count) { // Skip the first number of elements, and then take that same number of // elements from the beginning. return e.Skip(count).Concat(e.Take(count)); }

Por supuesto, debe haber alguna comprobación de errores en el anterior, pero esa es la premisa general.

Pensando en esto más, hay mejoras definitivas que se pueden hacer a este algoritmo que mejoraría el rendimiento.

Definitivamente puede aprovechar si la IEnumerable<T> implementa IList<T> o es una matriz, aprovechando el hecho de que está indexada.

Además, puede reducir el número de iteraciones que se requieren para omitir y tomar, que se tomarían dentro del cuerpo del mensaje.

Por ejemplo, si tiene 200 elementos y desea dividirlos en segmentos con un valor de 199, entonces requiere 199 (para el salto inicial) + 1 (para el artículo restante) + 199 (para la toma) iteraciones en el cuerpo del Método de corte Esto se puede reducir iterando a través de la lista una vez, almacenando los elementos en una lista que luego se concatena consigo misma (no requiere iteración).

En este caso, el intercambio aquí es memoria.

Con ese fin, propongo lo siguiente para el método de extensión:

public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int count) { // If the enumeration is null, throw an exception. if (source == null) throw new ArgumentNullException("source"); // Validate count. if (count < 0) throw new ArgumentOutOfRangeException("count", "The count property must be a non-negative number."); // Short circuit, if the count is 0, just return the enumeration. if (count == 0) return source; // Is this an array? If so, then take advantage of the fact it // is index based. if (source.GetType().IsArray) { // Return the array slice. return SliceArray((T[]) source, count); } // Check to see if it is a list. if (source is IList<T>) { // Return the list slice. return SliceList ((IList<T>) source); } // Slice everything else. return SliceEverything(source, count); } private static IEnumerable<T> SliceArray<T>(T[] arr, int count) { // Error checking has been done, but use diagnostics or code // contract checking here. Debug.Assert(arr != null); Debug.Assert(count > 0); // Return from the count to the end of the array. for (int index = count; index < arr.Length; index++) { // Return the items at the end. yield return arr[index]; } // Get the items at the beginning. for (int index = 0; index < count; index++) { // Return the items from the beginning. yield return arr[index]; } } private static IEnumerable<T> SliceList<T>(IList<T> list, int count) { // Error checking has been done, but use diagnostics or code // contract checking here. Debug.Assert(list != null); Debug.Assert(count > 0); // Return from the count to the end of the list. for (int index = count; index < list.Count; index++) { // Return the items at the end. yield return list[index]; } // Get the items at the beginning. for (int index = 0; index < list.Count; index++) { // Return the items from the beginning. yield return list[index]; } } // Helps with storing the sliced items. internal class SliceHelper<T> : IEnumerable<T> { // Creates a internal SliceHelper(IEnumerable<T> source, int count) { // Test assertions. Debug.Assert(source != null); Debug.Assert(count > 0); // Set up the backing store for the list of items // that are skipped. skippedItems = new List<T>(count); // Set the count and the source. this.count = count; this.source = source; } // The source. IEnumerable<T> source; // The count of items to slice. private int count; // The list of items that were skipped. private IList<T> skippedItems; // Expose the accessor for the skipped items. public IEnumerable<T> SkippedItems { get { return skippedItems; } } // Needed to implement IEnumerable<T>. // This is not supported. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw new InvalidOperationException( "This operation is not supported."); } // Skips the items, but stores what is skipped in a list // which has capacity already set. public IEnumerator<T> GetEnumerator() { // The number of skipped items. Set to the count. int skipped = count; // Cycle through the items. foreach (T item in source) { // If there are items left, store. if (skipped > 0) { // Store the item. skippedItems.Add(item); // Subtract one. skipped--; } else { // Yield the item. yield return item; } } } } private static IEnumerable<T> SliceEverything<T>( this IEnumerable<T> source, int count) { // Test assertions. Debug.Assert(source != null); Debug.Assert(count > 0); // Create the helper. SliceHelper<T> helper = new SliceHelper<T>( source, count); // Return the helper concatenated with the skipped // items. return helper.Concat(helper.SkippedItems); }


List<int> list1; List<int> list2 = new List<int>(list1);

o tu puedes

list2.AddRange(list1);

Para obtener una lista distinta usando LINQ

List<int> distinceList = list2.Distinct<int>().ToList<int>();


var newlist = oldlist.Skip(1).Concat(oldlist.Take(1));