2017-04-10 40 views
0

我有兩個需要比較的列表(carOptions和custOptions)。 這些列表的兩個都在我的Customer類象下面這樣:找到不在兩個列表中的值的最佳方法c#

public class CustomerDTO 
{ 
    public int CustomerId { get; set; } 
    //other props removed for brevity 
    public List<OptionDTO> SelectedCarOptions { get; set; } 
    public List<OptionDTO> SelectedCustomerOptions { get; set; } 
} 

     var existingData = _myRepository.GetDataByCustomer(customerId, year); 

     var existingCarOptions = existingData.Select(f => f.SelectedCarOptions); 
     var existingCustomerOptions = existingData.Select(f => f.SelectedCustomerOptions); 

existingData是CustomerDTO的IEnumerable,然後existingCarOptions和existingCustomerOptions是IEnumerable<List<OptionDTO>>

在該方法中,我有IEnumerable<OptionDTO>選項列表。被傳遞在我然後根據枚舉如下打破這種分解成車或客戶:

 var newCarOptions = options.Where(o => o.OptionTypeID == OptionType.CarOptions); 
     var newCustomerOptions = options.Where(o => o.OptionTypeID == OptionType.CustomerOptions).ToList(); 

我需要做的就是找到哪些選項是在一個集合,但沒有在 另一個。

我試着如下,但在Except上得到一個錯誤(我可能需要在該類中創建我自己的靜態方法),但我不確定這是最好的方法嗎?

 if (existingCarOptions.Count() != newCarOptions.Count()) 
     { 
      //var test = newCarOptions.Except(existingCarOptions); 
     } 

     if (existingCustomerOptions.Count() != newCustomerOptions.Count()) 
     { 
      //var test2 = newCustomerOptions.Except(existingCustomerOptions); 
     } 

是不是也該方法相當多的代碼 - 如果需要的話,但也許還有一個更簡單的方法,我可以做到這一點,我可以出其切分爲sperate的方法呢?

+2

什麼是你的'。除()'得到錯誤? –

+0

你是否缺少'使用System.Linq'指令? – Milen

+0

「existingCarOptions」和「newCarOptions」的泛型類型參數是什麼? – Fabjan

回答

1

具有p roperty稱爲Id,它唯一標識一個選項(如果不是這種情況,您必須相應地更改代碼),您可以使用HashSet s快速找到不匹配的OptionsDTO s,同時保持總體時間成本O(n)(其中n是最大值合併選項的數量)。

創建現有選項設置:

var existingCarOptions = existingData.SelectMany(d => d.SelectedCarOptions).Select(o => o.Id); 
var existingCustomerOptions = existingData.SelectMany(d => d.SelectedCustomerOptions).Select(o => o.Id); 

var existingCarOptionsIds = new HashSet<int>(existingCarOptions); 
var existingCustomerOptionsIds = new HashSet<int>(existingCustomerOptions); 

然後你解壓選項在現有臺失蹤:

var unmatchedCarOptions = newCarOptions.Where(o => !existingCarOptionsIds.Contains(o.Id)); 
var unmatchedCustomerOptions = newCustomerOptions.Where(o => !existingCustomerOptionsIds.Contains(o.Id)); 
+0

是的,有一個Id屬性。我會放棄這一點 –

1

如果要比較兩個類,你可以使用IEqualityComparer

public class OptionComparer : IEqualityComparer<OptionDTO> 
    { 
     public bool Equals(OptionDTO x, OptionDTO y) 
     { 
      if (object.ReferenceEquals(x, y)) 
      { 
       return true; 
      } 
      if (object.ReferenceEquals(x, null) || 
       object.ReferenceEquals(y, null)) 
      { 
       return false; 
      } 
      return x.OptionTypeID == y.OptionTypeID ; 
     } 

     public int GetHashCode(OptionDTO obj) 
     { 
      if (obj == null) 
      { 
       return 0; 
      } 
      return obj.OptionTypeID.GetHashCode(); 
     } 

如果使用這種可以識別出什麼是這些類平等的觀念。

現在,我們可以找到不同的價值觀..

public List<OptionDTO>CalculateDiffBetweenLists(List<OptionDTO> left, List<OptionDTO> right){ 

    List<OptionDTO> optionDiff; 


    optionDiff = left.Except(right, new OptionComparer()).ToList(); 

    return optionDiff ; 
} 
+0

正確的爲您需要的引用類型,要麼實現'IEquatable '或需要通過'IEqualityComparer ',想法仍然要覆蓋'GetHashCode'和用於平等比較的Equals'methods' –

0

另一種選擇是:

  1. 覆蓋EqualsGetHashCode方法在OptionDto類,它是從基本對象class的。也可以實現,IEquatable<T>通用接口,代碼會是這樣的(我假設像OptionDTOProp1OptionDTOProp2屬性),在沒有實際模式

    public bool Equals(OptionDTO other) 
    { 
    return other != null && 
         OptionDTOProp1 == other.OptionDTOProp1 && 
         OptionDTOProp2 == other.OptionDTOProp2; 
    } 
    
    public override bool Equals(object other) 
    { 
        return Equals(other as Test); 
    } 
    
    public override int GetHashCode() 
    { 
        return (OptionDTOProp1.GetHashCode() * 31 + OptionDTOProp2.GetHashCode() * 23); 
    } 
    

現在使用下面的通用擴展方法,這確實的在O(N)時間兩個列表之間的比較檢索,因爲它使用​​內部爲O(1)的搜索數據的:我假設OptionDTO

internal static class GenericListComparer 
{ 
    /// <summary> 
    ///  Select common elements in two collection using Hashset and return the list of second type elements. It can be 
    ///  modified to return the 
    ///  first type elements too. 
    /// </summary> 
    /// <param name="firstCollection"></param> 
    /// <param name="secondCollection"></param> 
    /// <returns></returns> 
    internal static IEnumerable<T> FindCommonElements<T>(this IEnumerable<T> firstCollection, 
                 IEnumerable<T> secondCollection) 
    { 
     // Create Hashset from first list 
     HashSet<int> firstCollectionHashSet = 
      new HashSet<int>(firstCollection.Select(element => element.GetHashCode())); 

     // Fetch the second type list elements as common list 
     List<T> commonList = 
      secondCollection.Where(element => firstCollectionHashSet.Contains(element.GetHashCode())).ToList(); 

     return commonList; 
    } 

    /// <summary> 
    ///  Select the elements that exist only in the Second list 
    /// </summary> 
    /// <param name="firstCollection"></param> 
    /// <param name="secondCollection"></param> 
    /// <returns></returns> 
    internal static IEnumerable<T> FindOnlySecondListElements<T>(this IEnumerable<T> firstCollection, 
    IEnumerable<T> secondCollection) 
    { 
     // Create Hashset from first list 
     HashSet<int> firstCollectionHashSet = 
      new HashSet<int>(firstCollection.Select(element => element.GetHashCode())); 

     // Fetch elements only in second type list 
     List<T> onlySecondListElements = 
      secondCollection.Where(element => !firstCollectionHashSet.Contains(element.GetHashCode())).ToList(); 

     return onlySecondListElements; 
    } 
} 
相關問題