首頁>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解決方案。

最新回復
  • 5月前
    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));
    

  • 5月前
    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 });
    

  • 5月前
    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();
    }
    

  • 5月前
    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));
    }
    

  • 5月前
    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讀取單元格值