首页>Program>source

如果我有类似IEnumerable的内容:

string[] items = new string[] { "a", "b", "c", "d" };

我想遍历所有成对的连续项(大小为2的滑动窗口).会是

("a","b"), ("b", "c"), ("c", "d")

我的解决方案是这个

   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)
 }

当我编写此代码时,我想知道.NET框架中是否已经存在可以执行相同操作的函数,并且该函数不仅针对成对,而且针对任何大小的元组。 恕我直言,应该有一种很好的方法来执行这种滑动窗口操作。

我使用C#2.0,我可以想象使用C#3.0(带有LINQ)有更多(更好的方法)来做到这一点,但是我主要对C#2.0解决方案感兴趣.但是,我也会欣赏C#3.0解决方案。

最新回答
  • 2021-1-11
    1 #

    在.NET 4中,这变得更加容易:-

    var input = new[] { "a", "b", "c", "d", "e", "f" };
    var result = input.Zip(input.Skip(1), (a, b) => Tuple.Create(a, b));
    

  • 2021-1-11
    2 #

    而不是要求元组(对)类型,为什么不只接受选择器:

    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);
        }
    }
    

    如果需要,可以让您跳过中间对象:

    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);
    

    或者您可以使用匿名类型:

    var pairs = items.Pairwise((x, y) => new { First = x, Second = y });
    

  • 2021-1-11
    3 #

    最简单的方法是使用ReactiveExtensions

    using System.Reactive;
    using System.Reactive.Linq;
    

    并使自己成为将工具一起打击的扩展方法

    public static IEnumerable<IList<T>> Buffer<T>(this IEnumerable<T> seq, int bufferSize, int stepSize)
    {
        return seq.ToObservable().Buffer(bufferSize, stepSize).ToEnumerable();
    }
    

  • 2021-1-11
    4 #

    晚了一点,但是作为所有这些扩展方法的替代方法,可以使用实际的"滑动" Collection 来保存(并丢弃)数据。

    这是我今天最后做的一个:

    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.
    }
    

    用法:

    int pairSize = 2;
    var slider = new SlidingWindowCollection<string>(pairSize);
    foreach(var item in items)
    {
        slider.Add(item);
        Console.WriteLine(string.Join(", ", slider));
    }
    

  • 2021-1-11
    5 #

    为方便起见,这里是@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);
        }
    }
    

  • location:Android Play服务65:缺少LocationClient
  • c#:打开xml Excel读取单元格值