Phần Mở Rộng Ix.NET
Bài viết này trình bày về các phương thức mở rộng trong thư viện Ix.NET, giúp cải thiện và thêm chức năng cho LINQ.
Buffer
Ix.NET Buffer Ix.NET BufferTest
Phương thức Buffer chia nguồn dữ liệu thành các khối theo kích thước và vị trí bắt đầu.
var ds = Enumerable.Range(0, 10);
var ketQua = ds.Buffer(3).ToList();
// ketQua.Count == 4
// ketQua[0] == { 0, 1, 2 }
// ketQua[1] == { 3, 4, 5 }
// ketQua[2] == { 6, 7, 8 }
// ketQua[3] == { 9 }
var ds = Enumerable.Range(0, 10);
var ketQua = ds.Buffer(5).ToList();
// ketQua.Count == 2
// ketQua[0] == { 0, 1, 2, 3, 4 }
// ketQua[1] == { 5, 6, 7, 8, 9 }
var ds = Enumerable.Empty<int>();
var ketQua = ds.Buffer(5).ToList();
// ketQua.Count == 0
var ds = Enumerable.Range(0, 10);
var ketQua = ds.Buffer(3, 2).ToList();
// ketQua.Count == 5
// ketQua[0] == { 0, 1, 2 }
// ketQua[1] == { 2, 3, 4 }
// ketQua[2] == { 4, 5, 6 }
// ketQua[3] == { 6, 7, 8 }
// ketQua[4] == { 8, 9 }
Case
Ix.NET Case Ix.NET CaseTest
Phương thức Case trả về một trong các Dictionary tùy thuộc vào kết quả của hàm callback.
var gt = 1;
var kyTu = 'd';
var ketQua = EnumerableEx.Case<int, char>(() => gt, new Dictionary<int, IEnumerable<char>>
{
{ 0, new[] { 'a' } },
{ 1, new[] { 'b' } },
{ 2, new[] { 'c' } },
{ 3, EnumerableEx.Defer(() => new[] { kyTu }) },
});
// ketQua.Single() == 'b'
// ketQua.Single() == 'b'
gt = 0;
// ketQua.Single() == 'a'
gt = 2;
// ketQua.Single() == 'c'
gt = 3;
// ketQua.Single() == 'd'
kyTu = 'e';
// ketQua.Single() == 'e'
gt = 4;
Assert.True(ketQua.IsEmpty());
var gt = 1;
var kyTu = 'd';
var ketQua = EnumerableEx.Case<int, char>(() => gt, new Dictionary<int, IEnumerable<char>>
{
{ 0, new[] { 'a' } },
{ 1, new[] { 'b' } },
{ 2, new[] { 'c' } },
{ 3, EnumerableEx.Defer(() => new[] { kyTu }) },
}, new[] { 'z' });
// ketQua.Single() == 'b'
// ketQua.Single() == 'b'
gt = 0;
// ketQua.Single() == 'a'
gt = 2;
// ketQua.Single() == 'c'
gt = 3;
// ketQua.Single() == 'd'
kyTu = 'e';
// ketQua.Single() == 'e'
gt = 4;
// ketQua.Single() == 'z'
Catch
Ix.NET Catch Ix.NET CatchTest
var ex = new MyException();
var ketQua = EnumerableEx.Throw<int>(ex).Catch<int, MyException>(e => { Assert.Same(ex, e); return new[] { 42 }; }).Single();
// ketQua == 42
var ex = new MyException();
var ketQua = EnumerableEx.Throw<int>(ex).Catch<int, Exception>(e => { Assert.Same(ex, e); return new[] { 42 }; }).Single();
// ketQua == 42
var ex = new MyException();
AssertThrows<MyException>(() =>
{
EnumerableEx.Throw<int>(ex).Catch<int, InvalidOperationException>(e => { Assert.True(false); return new[] { 42 }; }).Single();
});
var ds = Enumerable.Range(0, 10);
var ketQua = ds.Catch<int, MyException>(e => { Assert.True(false); return new[] { 42 }; });
// ketQua == ds
var dsArr = new[] { Enumerable.Range(0, 5), Enumerable.Range(5, 5) };
var ketQua = EnumerableEx.Catch(dsArr);
// ketQua == Enumerable.Range(0, 5)
var dsArr = new[] { Enumerable.Range(0, 5), Enumerable.Range(5, 5) };
var ketQua = dsArr.Catch();
// ketQua == Enumerable.Range(0, 5)
var dsArr = new[] { Enumerable.Range(0, 5), Enumerable.Range(5, 5) };
var ketQua = dsArr[0].Catch(dsArr[1]);
// ketQua == Enumerable.Range(0, 5)
Concat
Ix.NET Concat Ix.NET ConcatTest
Phương thức Concat nối các dãy dữ liệu lại với nhau.
var ketQua = new[]
{
new[] { 1, 2, 3 },
new[] { 4, 5 }
}.Concat();
// ketQua == { 1, 2, 3, 4, 5 }
var i = 0;
var dsArr = Enumerable.Range(0, 3).Select(x => Enumerable.Range(0, x + 1)).Do(_ => ++i);
var ketQua = dsArr.Concat().Select(x => i + " - " + x).ToList();
/*
ketQua == {
"1 - 0",
"2 - 0",
"2 - 1",
"3 - 0",
"3 - 1",
"3 - 2",
}
*/
Create
Ix.NET Create Ix.NET CreateTest
Phương thức Create tạo ra một dãy dữ liệu sử dụng coroutine.
private static IEnumerator<int> MyEnumerator()
{
yield return 1;
yield return 2;
}
var kiemTra = false;
var ketQua = EnumerableEx.Create<int>(() =>
{
kiemTra = true;
return MyEnumerator();
});
// kiemTra == false
var e = ketQua.GetEnumerator();
// kiemTra == true
HasNext(e, 1);
HasNext(e, 2);
NoNext(e);
kiemTra = false;
var f = ((IEnumerable)ketQua).GetEnumerator();
// kiemTra == true
var ds = EnumerableEx.Create<int>(async yield =>
{
var i = 0;
while (i < 10)
{
await yield.Return(i++);
}
});
var j = 0;
foreach (var phanTu in ds)
{
// phanTu == j
j++;
}
// j == 10
Defer
Ix.NET Defer Ix.NET DeferTest
Phương thức Defer tạo ra một dãy dữ liệu từ một hàm callback.
var i = 0;
var n = 5;
var ds = EnumerableEx.Defer(() =>
{
i++;
return Enumerable.Range(0, n);
});
// i == 0
// ds.ToList() == Enumerable.Range(0, n)
// i == 1
n = 3;
// ds.ToList() == Enumerable.Range(0, n)
// i == 2
Distinct / DistinctUntilChanged
Ix.NET Distinct / DistinctUntilChanged Ix.NET DistinctTest Ix.NET DistinctUntilChangedTest
Distinct loại bỏ các phần tử trùng lặp. DistinctUntilChanged loại bỏ các phần tử trùng lặp gần nhau.
var ketQua = Enumerable.Range(0, 10).Distinct(x => x % 5).ToList();
// ketQua == Enumerable.Range(0, 5)
private class MyEqualityComparer : IEqualityComparer<int>
{
public bool Equals(int x, int y)
{
return x % 2 == y % 2;
}
public int GetHashCode(int obj)
{
return EqualityComparer<int>.Default.GetHashCode(obj % 2);
}
}
var ketQua = Enumerable.Range(0, 10).Distinct(x => x % 5, new MyEqualityComparer()).ToList();
// ketQua == { 0, 1 }
var ketQua = new[] { 1, 2, 2, 3, 3, 3, 2, 2, 1 }.DistinctUntilChanged().ToList();
// ketQua == { 1, 2, 3, 2, 1 }
Do / DoWhile
Ix.NET Do / DoWhile Ix.NET DoTest Ix.NET DoWhileTest
Do thực thi một hàm khi duyệt qua các phần tử. DoWhile tạo một dãy mới bằng cách lặp lại các phần tử cho đến khi điều kiện không còn thỏa mãn.
var n = 0;
Enumerable.Range(0, 10).Do(x => n += x).ForEach(_ => { });
// n == 45
var n = 0;
Enumerable.Range(0, 10).Do(x => n += x, () => n *= 2).ForEach(_ => { });
// n == 90
Expand
Ix.NET Expand Ix.NET ExpandTest
Expand thực hiện các bước sau:
- Áp dụng hàm cho từng phần tử của nguồn dữ liệu, tạo ra các dãy con và kết nối chúng.
- Lặp lại quá trình này cho đến khi không còn phần tử nào.
var ketQua = new[] { 0 }.Expand(x => new[] { x + 1 }).Take(10).ToList();
// ketQua == Enumerable.Range(0, 10)
var ketQua = new[] { 3 }.Expand(x => Enumerable.Range(0, x)).ToList();
var ketQuaDuyet = new[] {
3,
0, 1, 2,
0,
0, 1,
0
};
// ketQua == ketQuaDuyet
Finally
Ix.NET Finally Ix.NET FinallyTest
var ketThuc = false;
var ds = Enumerable.Range(0, 2).Finally(() => ketThuc = true);
// ketThuc == false
var e = ds.GetEnumerator();
// ketThuc == false
HasNext(e, 0);
// ketThuc == false
HasNext(e, 1);
// ketThuc == false
NoNext(e);
// ketThuc == true
ForEach
Ix.NET ForEach Ix.NET ForEachTest
ForEach duyệt qua dãy dữ liệu và áp dụng hàm cho từng phần tử.
var n = 0;
Enumerable.Range(5, 3).ForEach(x => n += x);
// n == 5 + 6 +