2011-07-30 36 views
3

這是程序以及註釋。我有一個ListA和ListB。如果它出現在ListB中,我想將ListA的IsChecked = true。這是程序:LINQ查詢將列表中的少數項目選中爲

public class SomeClass 
{ 
    public bool IsChecked { get; set; } 
    public string Title { get; set; } 
} 

List<SomeClass> ListA = new List<SomeClass> 
{ 
    new SomeClass { IsChecked = false, Title = "A" }, 
    new SomeClass { IsChecked = false, Title = "B" }, 
    new SomeClass { IsChecked = false, Title = "C" }, 
    new SomeClass { IsChecked = false, Title = "D" }, 
    new SomeClass { IsChecked = false, Title = "E" }, 
    new SomeClass { IsChecked = false, Title = "F" }, 
}; 

List<SomeClass> ListB = new List<SomeClass> 
{ 
    new SomeClass { Title = "A" }, 
    new SomeClass { Title = "D" }, 
    new SomeClass { Title = "F" }, 
}; 

// some linq query at the end of which listA's Item containing Title = "A","D","F" will become true 

foreach (var item in ListA) 
{ 
    Console.WriteLine(item.Title + " " + item.IsChecked); 
} 
Console.ReadKey(); 

這是我想出了:

foreach (var item in ListB) 
{ 
    var listAItem = (from itemA in ListA 
        where itemA.Title == item.Title 
        select itemA).First(); //no need for FirstOrDefault() because it is always going to be present 

    listAItem.IsChecked = true; 
} 

但是這看起來非常低效的。有沒有更好的方式使用Linq來做到這一點?我只需要LINQ中的解決方案。提前:)

回答

5

你可以使用一個Join這樣的:

var itemAsToBeChecked = from itemA in ListA 
         join itemB in ListB on itemA.Title equals itemB.Title 
         select itemA; 

foreach (var itemA in itemAsToBeChecked) 
    itemA.IsChecked = true; 

相信微軟的落實Join將首先在ListB創建Title查找(Lookup<,>)到SomeClass列舉ListA,符合各itemA與前查找,因爲它去。這應該比現在的解決方案更有效率。

您也可以考慮使用HashSet<T>如果你喜歡:

var titlesToBeChecked = new HashSet<string>(ListB.Select(itemB => itemB.Title)); 
var itemAsToBeChecked = ListA.Where(itemA => titlesToBeChecked.Contains(itemA.Title)); 

foreach (var itemA in itemAsToBeChecked) 
    itemA.IsChecked = true; 

當然,它可能是有意義這裏實現你的類型IEqualityComparer<T>如其他人所說的,特別是如果Title基於平等的定義是通常在你的程序中使用。

+0

+1。我喜歡你的解決方案。 BrokenGlass提供的Intersect解決方案如何?這是否也會創建一個查詢?任何想法? – TCM

+0

@Anthony:如果你的類型有適當的等式實現,或者你提供了一個合適的'IEqualityComparer','Intersect'就可以正常工作。但我並不喜歡在這裏交叉,因爲這會讓讀者感到困惑。當每個列表中的匹配項目在各種可能的意義上都「相等」時,通常使用「相交」。但是你非常關心結果應該來自哪個列表......(不是說這個方法的文檔是模糊的,但是它會很奇怪)。 – Ani

2

你可以做

foreach(var item in ListA.Where(x => ListB.Contains(x))) 
    item.IsChecked = true; 

感謝這需要你的SomeClass類來實現IEquatable<SomeClass>到Title屬性比較:

public class SomeClass : IEquatable<SomeClass> 
{ 
    public bool IsChecked { get; set; } 
    public string Title { get; set; } 

    public bool Equals(SomeClass other) 
    { 
     return this.Title == other.Title; 
    } 
} 

或者您可以使用Intersect()這將要求您提供IEqualityComparer

foreach (var item in ListA.Intersect(ListB, new SomeClassComparer())) 
    item.IsChecked = true; 

... 
public class SomeClassComparer : IEqualityComparer<SomeClass> 
{ 
    public bool Equals(SomeClass x, SomeClass y) 
    { 
     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 
     return x.Title == y.Title; 
    } 

    public int GetHashCode(SomeClass obj) 
    { 
     return obj.Title.GetHashCode(); 
    } 
} 
1

一個解決方案(不要求執行IComparableIEquatable,如果你有過那類沒有控制):

foreach (var item in ListA.Where(a => ListB.Any(b => b.Title == a.Title))) 
{ 
    item.IsChecked = true; 
} 

請記住,除非你想,你需要這樣的foreach重寫ListA。 Linq是一種查詢語言,不應該用來修改現有列表。使用純Linq隱藏你的意圖。可能有一種方法可以正確使用.Join.Zip來返回新的ListA,但使用傳統結構修改總是更好。

1
var q = from i1 in listA 
     from i2 in listB 
     where i1.Title == it2.Title 
     select i1; 

foreach (var i in q) 
{ 
    i.IsChecked = true; 
} 
1

我用Enumerable.Intersect操作:

public class SomeClass : IEquatable<SomeClass> 
{ 
    public bool IsChecked { get; set; } 
    public string Title { get; set; } 

    public bool Equals(SomeClass other) 
    { 
     //Check whether the compared object is null. 
     if (ReferenceEquals(other, null)) return false; 

     //Check whether the compared object references the same data. 
     if (ReferenceEquals(this, other)) return true; 

     //Check whether SomeClass's properties are equal. 
     return Title.Equals(other.Title); 
    } 

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects. 
    public override int GetHashCode() 
    { 
     //Get hash code for the Title field if it is not null. 
     int hashSomeClassTitle = Title == null ? 0 : Title.GetHashCode(); 

     //Calculate the hash code for SomeClass. 
     return hashSomeClassTitle; 
    } 
} 

實施EqualsGetHashCode後,你是好去:

var intersection = ListA.Intersect(ListB); 

foreach (var item in intersection) 
{ 
    item.IsChecked = true; 

    Console.WriteLine(item.Title + " " + item.IsChecked); 
} 
相關問題