用Linq找出有搭到的項目

  • 4795
  • 0

用Linq找出有搭到的項目

Dotblogs 的標籤: , ,

有個需求如下:

  1. 原始資料來源有 1 ~ 10。
  2. 另一個資料表有兩個欄位,儲存多筆起迄區間,例如:2~3、3~5、8~9。
  3. 要找出原始來源中,和起迄區間有交集的項目。

用 Linqpad 的 C# Statement 模式,弄個範例程式如下:

var list = Enumerable.Range(1, 10);

DataTable dt = new DataTable();
dt.Columns.Add("Begin", System.Type.GetType("System.Int32"));
dt.Columns.Add("End", System.Type.GetType("System.Int32"));
dt.Rows.Add(2, 3);
dt.Rows.Add(3, 5);
dt.Rows.Add(8, 9);
dt.Dump();

var q1= (from x in dt.AsEnumerable() 
    select Enumerable.Range(x.Field<int>("Begin"), x.Field<int>("End")-x.Field<int>("Begin")+1))
    .SelectMany (v => v);
var query = list.Intersect(q1);
query.Count().Dump();
query.Dump();

想法是,先把所有可以交集的區間展開(Enumerable.Rang )、扁平化(SelectMany),然後用交集(Intersect)函數即可。特別注意的是,Enumerable.Rang 的第二個參數,是 Count,不是「迄」:

public static IEnumerable<int> Range(
      int start,
      int count
  )

參數
start
型別: System.Int32 
序列中第一個整數的值。

count
型別: System.Int32 
要產生的循序整數數目。

傳回值
型別: System.Collections.Generic.IEnumerable <Int32>
C# 中的 IEnumerable<Int32> 或 Visual Basic 中的 IEnumerable(Of Int32),其中包含循序整數的範圍。

以上範例是用 int 來做,所以可以用 Enumerable.Range 來展開,若是非 int 項目,就自訂展開的方法來處理,但精神相同。

=======補充另外兩種版本========

直接 join + where 版:

var q2 = (from i in list
	from x in dt.AsEnumerable()
	where i >= x.Field<int>("Begin") && i <= x.Field<int>("End")
	select i).Distinct();

用匿名方法:

Func<int, int, int, bool> isMatch = (i, iBegin, iEnd) => (i >= iBegin && i <= iEnd);

var q2 = (from i in list
	from x in dt.AsEnumerable()
	where isMatch(i, x.Field<int>("Begin"), x.Field<int>("End"))
	select i).Distinct();

 

--------
沒什麼特別的~
不過是一些筆記而已