2012-12-29 69 views
1

我將如何寫這與linq?我將如何優化LINQ的嵌套for循環

foreach (var to in allCurrentTradeObjects) 
{ 
    foreach (var ro in theseWantMe) 
    { 
     if (ro.Type != to.Type 
       || ro.MaxRent < to.Rent 
       || ro.MinRooms > to.Rooms 
       || ro.MinSquareMeters > to.SquareMeters 
       || ro.MaxPrice < to.Price 
       || ro.MinFloors > to.Floors 
       || ro.TradeObjectId == to.TradeObjectId 
       || ro.TradeObjectId == myTradeObject.TradeObjectId) 
     { 
      continue; 
     } 
     RatingListTriangleModel rlt = new RatingListTriangleModel 
     { 
      To1Id = myTradeObject.TradeObjectId, 
      To2Id = to.TradeObjectId, 
      To3Id = ro.TradeObjectId, 
      T1OnT2Rating = 0, 
      T2OnT3Rating = 0, 
      T3OnT1Rating = 0, 
      TotalRating = 0 
     }; 

     //_context.RatingListTriangle.Add(rlt); 
     this.InsertOrUpdate(rlt); 

    } 
} 
this.Save(); 
+0

優化是爲了什麼? –

回答

5
var query = from to in allCurrentTradeObjects 
      from ro in theseWantMe 
      where ro.Type == to.Type && 
        ro.MaxRent >= to.Rent && 
        ro.MinRooms <= to.Rooms && 
        ro.MinSquareMeters <= to.SquareMeters && 
        ro.MaxPrice >= to.Price && 
        ro.MinFloors <= to.Floors && 
        ro.TradeObjectId != to.TradeObjectId && 
        ro.TradeObjectId != myTradeObject.TradeObjectId 
      select new RatingListTriangleModel 
      { 
       To1Id = myTradeObject.TradeObjectId, 
       To2Id = to.TradeObjectId, 
       To3Id = ro.TradeObjectId, 
       T1OnT2Rating = 0, 
       T2OnT3Rating = 0, 
       T3OnT1Rating = 0, 
       TotalRating = 0 
      }; 

foreach(var rlt in query) 
    this.InsertOrUpdate(rlt); 

this.Save(); 
+0

讓我們來看看linq吧。我的意思是這種方式更好。 :(:(:(+1反正 –

+2

@TonyHopkinson我想這是可讀性優化.. –

+1

庵,可讀性對我將是對構造的過載,並在RO和某種比較,雖然扭轉了邏輯並擺脫該continue語句使代碼100%可讀性更強直客。我花了五分鐘,甚至毫無察覺。 –

1

以下是方法的語法。

allCurrentTradeObjects.Select (
      to => to.theseWantMe.Where (ro => !(ro.Type != to.Type 
       || ro.MaxRent < to.Rent 
       || ro.MinRooms > to.Rooms 
       || ro.MinSquareMeters > to.SquareMeters 
       || ro.MaxPrice < to.Price 
       || ro.MinFloors > to.Floors 
       || ro.TradeObjectId == to.TradeObjectId 
       || ro.TradeObjectId == myTradeObject.TradeObjectId)) 
       .Select({ 
          var rlt = new RatingListTriangleModel 
           { 
           To1Id = myTradeObject.TradeObjectId, 
           To2Id = to.TradeObjectId, 
           To3Id = ro.TradeObjectId, 
           T1OnT2Rating = 0, 
           T2OnT3Rating = 0, 
           T3OnT1Rating = 0, 
           TotalRating = 0 
          }; 
          this.InsertOrUpdate(rlt); 
          return rlt; 
         }).ToArray(); 
this.Save(); 
+0

找不到在哪裏'theseWantMe'集合中查詢。誰upvoted這個.. –

+0

我錯過了它的第一眼,現予以更正。 – Tilak

+0

'theseWantMe'不是'ro'屬性.. –

2

開始通過嵌套循環的骨架轉換爲LINQ:

var rtls = allCurrentTradeObjects 
    .SelectMany(to => theseWantMe.Select(ro => new {to, ro})); 

這讓你對{to, ro}的列表。現在,通過反向continue條件添加過濾:

var rtls = allCurrentTradeObjects 
    .SelectMany(to => theseWantMe.Select(ro => new {to, ro})); 
    .Where(p => p.ro.Type == p.to.Typpe && p.ro.MaxRent >= p.to.Rent && ...) 

最後,添加一個Select叫`新:

var rtls = allCurrentTradeObjects 
    .SelectMany(to => theseWantMe.Select(ro => new {to, ro})); 
    .Where(p => p.ro.Type == p.to.Typpe && p.ro.MaxRent >= p.to.Rent && ...) 
    .Select(p => new RatingListTriangleModel { 
     To1Id = myTradeObject.TradeObjectId, 
     To2Id = p.to.TradeObjectId, 
     To3Id = p.ro.TradeObjectId, 
     ... 
    }); 

隨着rtls名單在手,你可以在一個循環中調用InsertOrUpdate

0

爲了增加可讀性,我將通過重構的複雜狀況開始並將其移動到一個整潔的小功能(它也可以是對象的方法)

private bool IsMatchingTradeObject (TradeObject to, SomeOtherObject ro, int TradeObjectId) 
{ 
    return ro.Type == to.Type && 
        ro.MaxRent >= to.Rent && 
        ro.MinRooms <= to.Rooms && 
        ro.MinSquareMeters <= to.SquareMeters && 
        ro.MaxPrice >= to.Price && 
        ro.MinFloors <= to.Floors && 
        ro.TradeObjectId != to.TradeObjectId && 
        ro.TradeObjectId != TradeObjectId; 
} 

其次,我會做與創建相同並初始化RatingListTriangleModel,即將其移動到一個小方法並給它一個有意義的名稱。

private RatingListTriangleModel CreateModel(TradeObject to, SomeOtherObject ro, int TradeObjectId) 
{ 
    return new RatingListTriangleModel 
    { 
     To1Id = myTradeObject.TradeObjectId, 
     To2Id = to.TradeObjectId, 
     To3Id = ro.TradeObjectId, 
     T1OnT2Rating = 0, 
     T2OnT3Rating = 0, 
     T3OnT1Rating = 0, 
     TotalRating = 0 
    }; 

剩下的代碼更易於閱讀

foreach (var to in allCurrentTradeObjects) 
    foreach (var ro in theseWantMe) 
     if (IsMatchingTradeObject(to, ro, myTradeObject.TradeObjectId)) 
     this.InsertOrUpdate(CreateModel(to, ro, myTradeObject.TradeObjectId)); 

this.Save(); 

這個轉換爲LINQ很簡單:

allCurrentTradeObjects.Select (
    to => to.Where ( 
    ro => IsMatchingTradeObject (to, ro, myTradeObject.TradeObjectId) 
    ) 
).Select(
    { 
     this.InsertOrUpdate(CreateModel(to, ro, myTradeObject.TradeObjectId)); 
     return null; 
    } 
); 
this.Save(); 

然而,的foreach循環似乎更容易閱讀。

1

有很多答案在這裏提倡的SelectMany(或雙)。這些是「優化可讀性」的答案,因爲它們不會改變此操作的N * M嵌套循環性能。

如果這兩個集合是大你不應該使用這種方法。相反,您應該利用兩個集合之間良好定義的關係,並使用Enumerable.Join中的散列將操作減少到N + M。

var myTradeObject = GetThatOneObject(); 

IEnumerable<RatingListTriangleModel> query = 
    from to in allCurrentTradeObjects 
//pre-emptively filter to the interesting objects in the first collection 
    where to.TradeObjectId == myTradeObject.TradeObjectId 
//take advantage of hashing in Enumerable.Join - theseWantMe is enumerated once 
    join ro in theseWantMe 
    on to.Type equals ro.Type 
//remaining matching criteria 
    where to.Rent <= ro.MaxRent //rent is lower than max 
    && ro.MinRooms <= to.Rooms //rooms are higher than min 
    && ro.MinSquareMeters <= to.SquareMeters //area is higher than min 
    && to.Price <= ro.MaxPrice  //price is lower than max 
    && ro.MinFloors <= to.Floors // floors are higher than min 
    && to.TradeObjectId != ro.TradeObjectId //not same trade object 
    select CreateRatingListTriangleModel(myTradeObject, to, ro); 

foreach(RatingListTriangleModel row in query) 
{ 
    this.InsertOrUpdate(row); 
} 
this.Save(); 
+0

感謝大衛,我嘗試過,但我無法弄清楚,爲什麼我沒有收到我的查詢任何結果使用這個? –