2012-01-16 37 views
6

Tôi đang làm việc trên một số mã C# đối phó với các vấn đề như di chuyển trung bình, nơi tôi thường cần phải có một List/IEnumerable và làm việc trên khối dữ liệu liên tiếp. Mô-đun F # Seq có chức năng tuyệt vời, được cửa sổ, trong đó lấy một Chuỗi, trả về một chuỗi các phần tử liên tiếp.Có tương đương với F # Seq.windowed trong C# không?

C# có chức năng tương đương out-of-the-box với LINQ không?

+0

Người dùng đã cung cấp câu trả lời được chấp nhận thừa nhận là đã sai, bạn có thể cân nhắc việc chọn một người khác ngay bây giờ. – Kev

Trả lời

5

Bạn luôn có thể gọi SeqModule.Windowed từ C#, bạn chỉ cần tham chiếu FSharp.Core.Dll. Các tên hàm cũng hơi nham nhở, vì vậy bạn gọi Windowed hơn windowed, để nó phù hợp với C# vốn hóa ước

+0

Ở đây, ở đây, làm điều đó tất cả các thời gian! Seq.singleton, FSharpSet, bạn đặt tên cho nó. Khi tôi phải viết mã trong C#, tôi thường sử dụng F # stdlib. Làm thế nào tôi có thể sống mà không có nó! – kkm

+1

Đó là 'SeqModule.Windowed' thực sự. –

2

Bạn luôn có thể cuộn của riêng bạn (hoặc dịch một từ F # core):

let windowed windowSize (source: seq<_>) =  
    checkNonNull "source" source 
    if windowSize <= 0 then invalidArg "windowSize" (SR.GetString(SR.inputMustBeNonNegative)) 
    seq { let arr = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked windowSize 
      let r = ref (windowSize-1) 
      let i = ref 0 
      use e = source.GetEnumerator() 
      while e.MoveNext() do 
       arr.[!i] <- e.Current 
       i := (!i + 1) % windowSize 
       if !r = 0 then 
        yield Array.init windowSize (fun j -> arr.[(!i+j) % windowSize]) 
       else 
       r := (!r - 1) } 

Nỗ lực của tôi trông như thế này, nó chậm hơn so với việc chỉ gọi F # trực tiếp (theo gợi ý của John Palmer). Tôi đoán đó là vì F # sử dụng một mảng không được kiểm soát .:

public static IEnumerable<T[]> Windowed<T>(this IEnumerable<T> list, int windowSize) 
{ 
    //Checks elided 
    var arr = new T[windowSize]; 
    int r = windowSize - 1, i = 0; 
    using(var e = list.GetEnumerator()) 
    { 
     while(e.MoveNext()) 
     { 
      arr[i] = e.Current; 
      i = (i + 1) % windowSize; 
      if(r == 0) 
       yield return ArrayInit<T>(windowSize, j => arr[(i + j) % windowSize]); 
      else 
       r = r - 1; 
     } 
    } 
} 
public static T[] ArrayInit<T>(int size, Func<int, T> func) 
{ 
    var output = new T[size]; 
    for(var i = 0; i < size; i++) output[i] = func(i); 
    return output; 
} 
+0

Thay thế cuộc gọi thành 'ArrayInit' bằng' var arrR = new T [windowSize]; cho (int j = 0; j Daniel

+1

'Seq.windowed' sử dụng' zeroCreateUnchecked', nhưng nó chỉ bỏ qua xác nhận tham số 'size' (tức là,' nếu size <0 thì invalidArg ... '). Nó không tránh kiểm tra giới hạn. Điều đó được thực hiện theo quyết định của JITer, tôi tin. – Daniel

+0

@Daniel, rất vui được gặp ai đó lấy mồi :) Tôi không thể nhận được kết quả của bạn. Nếu tôi làm 'var list = Enumerable.Range (0, 100000); var sw = Stopwatch.StartNew(); int count = list.Windowed (15) .Count(); sw.Stop(); 'và sau đó cùng một điều với' Microsoft.FSharp.Collections.SeqModule.Windowed' (trên một phạm vi mới), C# luôn mất khoảng hai lần ... – Benjol

1

Các Reactive Extensions có một vài nhà khai thác để giúp với điều này, chẳng hạn như BufferWindow. Các phần mở rộng tương tác, có thể được tìm thấy trong nhánh thử nghiệm, thêm chúng và một số lượng đáng kể các toán tử bổ sung vào LINQ.

Các vấn đề liên quan