c# - impares - suma de numeros pares con while en c++
RepeticiĆ³n por pares en C#o ventana deslizante enumerador (11)
Algo como esto:
public static IEnumerable<TResult> Pairwise<T, TResult>(this IEnumerable<T> enumerable, Func<T, T, TResult> selector)
{
var previous = enumerable.First();
foreach (var item in enumerable.Skip(1))
{
yield return selector(previous, item);
previous = item;
}
}
Si tengo un IEnumerable como:
string[] items = new string[] { "a", "b", "c", "d" };
Me gustaría pasar por todos los pares de elementos consecutivos (ventana deslizante de tamaño 2). Cuál podría ser
("a","b"), ("b", "c"), ("c", "d")
Mi solución fue esta
public static IEnumerable<Pair<T, T>> Pairs(IEnumerable<T> enumerable) {
IEnumerator<T> e = enumerable.GetEnumerator(); e.MoveNext();
T current = e.Current;
while ( e.MoveNext() ) {
T next = e.Current;
yield return new Pair<T, T>(current, next);
current = next;
}
}
// used like this :
foreach (Pair<String,String> pair in IterTools<String>.Pairs(items)) {
System.Out.PrintLine("{0}, {1}", pair.First, pair.Second)
}
Cuando escribí este código, me pregunté si ya hay funciones en .NET Framework que hagan lo mismo y que lo hagan no solo para pares sino para tuplas de cualquier tamaño. En mi humilde opinión, debería haber una buena manera de hacer este tipo de operaciones de ventana deslizante.
Uso C # 2.0 y puedo imaginar que con C # 3.0 (con LINQ) hay más (y mejores) formas de hacerlo, pero estoy interesado principalmente en las soluciones C # 2.0. Sin embargo, también apreciaré las soluciones C # 3.0.
Aquí está mi solución usando una pila. Es corto y conciso.
string[] items = new string[] { "a", "b", "c", "d" };
Stack<string> stack = new Stack<string>(items.Reverse());
while(stack.Count > 1)
{
Console.WriteLine("{0},{1}", stack.Pop(), stack.Peek());
}
El módulo F # Seq
define la función pairwise sobre IEnumerable<T>
, pero esta función no está en .NET framework.
Si ya estuviera en el marco de .NET, en lugar de devolver pares, probablemente aceptaría una función de selector debido a la falta de soporte para tuplas en idiomas como C # y VB.
var pairs = ns.Pairwise( (a, b) => new { First = a, Second = b };
No creo que ninguna de las respuestas aquí realmente mejore en la implementación simple de tu iterador, que me pareció la más natural (¡y el póster dahlbyk por el aspecto de las cosas!) También.
En .NET 4, esto se vuelve aún más fácil: -
var input = new[] { "a", "b", "c", "d", "e", "f" };
var result = input.Zip(input.Skip(1), (a, b) => Tuple.Create(a, b));
En lugar de requerir un tipo de tupla (par), ¿por qué no simplemente aceptar un selector?
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
{
TSource previous = default(TSource);
using (var it = source.GetEnumerator())
{
if (it.MoveNext())
previous = it.Current;
while (it.MoveNext())
yield return resultSelector(previous, previous = it.Current);
}
}
Lo que le permite omitir el objeto intermedio si lo desea:
string[] items = new string[] { "a", "b", "c", "d" };
var pairs = items.Pairwise((x, y) => string.Format("{0},{1}", x, y));
foreach(var pair in pairs)
Console.WriteLine(pair);
O puede usar un tipo anónimo:
var pairs = items.Pairwise((x, y) => new { First = x, Second = y });
Expandir la respuesta anterior para evitar el enfoque O (n 2 ) mediante el uso explícito del iterador pasado:
public static IEnumerable<IEnumerable<T>> Tuples<T>(this IEnumerable<T> input, int groupCount) {
if (null == input) throw new ArgumentException("input");
if (groupCount < 1) throw new ArgumentException("groupCount");
var e = input.GetEnumerator();
bool done = false;
while (!done) {
var l = new List<T>();
for (var n = 0; n < groupCount; ++n) {
if (!e.MoveNext()) {
if (n != 0) {
yield return l;
}
yield break;
}
l.Add(e.Current);
}
yield return l;
}
}
Para C # 2, antes de los métodos de extensión, suelte "this" del parámetro de entrada y llame como método estático.
Implementación de Pairs
alternativas, utilizando el último par para almacenar el valor anterior:
static IEnumerable<Pair<T, T>> Pairs( IEnumerable<T> collection ) {
Pair<T, T> pair = null;
foreach( T item in collection ) {
if( pair == null )
pair = Pair.Create( default( T ), item );
else
yield return pair = Pair.Create( pair.Second, item );
}
}
Implementación simple de Window
(solo segura para uso privado, si la persona que llama no guarda las matrices devueltas, vea la nota):
static IEnumerable<T[]> Window( IEnumerable<T> collection, int windowSize ) {
if( windowSize < 1 )
yield break;
int index = 0;
T[] window = new T[windowSize];
foreach( var item in collection ) {
bool initializing = index < windowSize;
// Shift initialized window to accomodate new item.
if( !initializing )
Array.Copy( window, 1, window, 0, windowSize - 1 );
// Add current item to window.
int itemIndex = initializing ? index : windowSize - 1;
window[itemIndex] = item;
index++;
bool initialized = index >= windowSize;
if( initialized )
//NOTE: For public API, should return array copy to prevent
// modifcation by user, or use a different type for the window.
yield return window;
}
}
Ejemplo de uso:
for( int i = 0; i <= items.Length; ++i ) {
Console.WriteLine( "Window size {0}:", i );
foreach( string[] window in IterTools<string>.Window( items, i ) )
Console.WriteLine( string.Join( ", ", window ) );
Console.WriteLine( );
}
La forma más fácil es usar ReactiveExtensions
using System.Reactive;
using System.Reactive.Linq;
y hazte un método de extensión para kit bash esto juntos
public static IEnumerable<IList<T>> Buffer<T>(this IEnumerable<T> seq, int bufferSize, int stepSize)
{
return seq.ToObservable().Buffer(bufferSize, stepSize).ToEnumerable();
}
Solo por comodidad, aquí hay una versión sin selector de la respuesta de @ dahlbyk.
public static IEnumerable<Tuple<T, T>> Pairwise<T>(this IEnumerable<T> enumerable)
{
var previous = default(T);
using (var e = enumerable.GetEnumerator())
{
if (e.MoveNext())
previous = e.Current;
while (e.MoveNext())
yield return Tuple.Create(previous, previous = e.Current);
}
}
Solución C # 3.0 (lo siento :)
public static IEnumerable<IEnumerable<T>> Tuples<T>(this IEnumerable<T> sequence, int nTuple)
{
if(nTuple <= 0) throw new ArgumentOutOfRangeException("nTuple");
for(int i = 0; i <= sequence.Count() - nTuple; i++)
yield return sequence.Skip(i).Take(nTuple);
}
Este no es el mejor rendimiento del mundo, pero es agradable de ver.
En realidad, lo único que hace de esto una solución C # 3.0 es la construcción .Skip.Take, así que si simplemente cambias eso para agregar los elementos de ese rango a una lista, debería ser oro para 2.0. Dicho eso, todavía no está funcionando.
Un poco tarde para la fiesta, pero como alternativa a todos estos métodos de extensión, uno podría usar una Collection
"deslizante" real para contener (y descartar) los datos.
Aquí hay uno que terminé haciendo hoy:
public class SlidingWindowCollection<T> : ICollection<T>
{
private int _windowSize;
private Queue<T> _source;
public SlidingWindowCollection(int windowSize)
{
_windowSize = windowSize;
_source = new Queue<T>(windowSize);
}
public void Add(T item)
{
if (_source.Count == _windowSize)
{
_source.Dequeue();
}
_source.Enqueue(item);
}
public void Clear()
{
_source.Clear();
}
...and just keep forwarding all other ICollection<T> methods to _source.
}
Uso:
int pairSize = 2;
var slider = new SlidingWindowCollection<string>(pairSize);
foreach(var item in items)
{
slider.Add(item);
Console.WriteLine(string.Join(", ", slider));
}