2012-04-03 28 views
6

Có cách nào "LINQ" để có lựa chọn dữ liệu có điều kiện, tức là chọn từ nguồn khác nếu nguồn đầu tiên trống? Một ví dụ là nếu bạn có cấu trúc cây của các mục và bạn muốn lấy một số nội dung từ gốc hoặc nếu nó trống, từ đó là con.Lựa chọn có điều kiện trong LINQ (chọn thay thế nếu trống)

Tôi có ví dụ sau:, phương pháp khuyến nông

IEnumerable<Item> items = ...; 
// Item has a Assets property that returns IEnumerable<Asset> 
// Item has a SubItems property that returns IEnumerable<Item> 
// i.e. other items with assets in them 

// getting assets from a "main" item 
var assets = item.Assets.Where(a => HasRelevantAsset(a)); 

// if there were no relevant assets in the "main" item 
if (!assets.Any()) { 
    // then reselect from "subitems" assets instead 
    assets = item.SubItems.SelectMany(item => 
     item.Assets.Where(a => HasRelevantAsset(a))); 
} 

// HasRelevantAsset(Asset) is a static method that returns 
// true if it is the asset that is needed 
+0

Điều này có vẻ giống như sử dụng khá tốt cho ?? toán tử - 'var asset = something ?? something_else'. Nó sẽ không hoạt động, nhưng nó sẽ là tốt đẹp nếu nó đã làm. – zmbq

Trả lời

1

Tôi tin rằng cách LINQ sẽ xem xét một chút xấu xí

var assets = item.Any(a=>HaRelevantAsset(a)) ? item.Where(a => HasRelevantAsset(a)) : 
        item.SubItems.SelectMany(item => 
          item.Assets.Where(a => HasRelevantAsset(a))); 

tôi sẽ lựa chọn cho các biến thể khác

public static IEnumerable<Asset> SelectRelevantAssets(this Item item) 
{ 
    var assetsInItemFound = false; 
    foreach (var asset in item.Assets) 
    { 
     if (HasRelevantAsset(asset)) 
     { 
      assetsInItemFound = true; 
      yield return asset; 
     } 
    } 
    if (assetsInItemFound) 
    { 
     yield break; 
    } 
    else 
    { 
     foreach (var subItem in item.SubItems)   
      foreach (var asset in subItem.Assets) 
       if (HasRelevantAsset(asset)) 
        yield return asset; 
    } 
} 





Trước tiên tôi muốn thử một cuộc gọi đệ quy để SelectRelevantAssets, tôi nghĩ rằng sẽ như thế nào

if (!assetsInItemFound) 
     { 
      yield break; 
     } 
     else 
     { 
      foreach (var subItem in item.SubItems)   
       foreach (var asset in SelectRelevantAssets(subItem)) 
         yield return asset; 
     } 

Nhưng điều này sẽ bao gồm các tài sản được tìm thấy trong bộ sưu tập Các hạng mục tài sản của subitem