2013-10-28 20 views
4

對我有ObservableCollection aList b從名字出現其他列表

現在我想從集合中刪除有其表b相當於a元素的ObservableCollection項目中移除。

我的代碼在這一刻:

public static void CrossRemove<TFirst, TSecond>(this ObservableCollection<TFirst> collection, IEnumerable<TSecond> secondCollection, Func<TFirst, TSecond, bool> predicate) 
{ 
    collection.Where(first => secondCollection.Any(second => predicate(first, second))) 
     .ToList().ForEach(item => collection.Remove(item)); 
} 

用法:

ObservableCollection<string> first = new ObservableCollection<string> { "1", "2", "3", "4", "5", "6", "k" }; 

IEnumerable<int> second = new List<int> { 2, 3, 5 }; 

first.CrossRemove(second, (x, y) => x == y.ToString()); 

這個代碼刪除 「2」, 「3」 和 「5」 從收集離開 「1」, 「4」 ,「6」和「k」。

在我的真實代碼ab包含繼承自相同interface的元素,我比較了該接口中的屬性,但我無法採取任何冒險行爲。

我不能創建一個新的列表,因爲它綁定到wpf視圖,並且如果我這樣做而不是刪除項目,將會出現可見的毛刺。

有沒有更好/更快的方式做到這一點?

+0

你的問題到底是什麼? –

+0

抱歉,更新 – Adassko

+1

我想不出一個更好的方法。你必須堅持這種方法。可能有人帶來更好的解決方案:) –

回答

1

您可以使您的第二個集合HashSet<T>更快查找。我也改變了你的ForEach to a foreach。這很容易用屬性來演示,就像你原來的那樣。

void Main() 
{ 
    ObservableCollection<MyClass> first = new ObservableCollection<MyClass> { "1", "2", "3", "4", "5", "6", "k" }; 

    ISet<IMyInterface> second = new HashSet<IMyInterface>(new MyClass2[] { 2, 3, 5 }, new MyEqualityComparer()); 

    first.CrossRemove(second); 

    Console.WriteLine(string.Join(", ", first.Select(x => x.MyProperty))); 
    // 1, 4, 6, k 
} 
public interface IMyInterface 
{ 
    string MyProperty { get; set; } 
} 
public class MyEqualityComparer : IEqualityComparer<IMyInterface> 
{ 
    public bool Equals(IMyInterface a, IMyInterface b) 
    { 
     return a.MyProperty == b.MyProperty; 
    } 
    public int GetHashCode(IMyInterface obj) 
    { 
     return obj.MyProperty.GetHashCode(); 
    } 
} 
public static class Extensions 
{ 
    public static void CrossRemove<TFirst, TSecond>(this ObservableCollection<TFirst> collection, ISet<TSecond> set) where TFirst : TSecond 
    { 
     foreach (var item in collection.Where(item => set.Contains(item)).ToList()) 
      collection.Remove(item); 
    } 
} 
public class MyClass : IMyInterface 
{ 
    public string MyProperty { get; set; } 
    public static implicit operator MyClass(string s) 
    { 
     return new MyClass { MyProperty = s }; 
    } 
} 
public class MyClass2 : IMyInterface 
{ 
    public string MyProperty { get; set; } 
    public static implicit operator MyClass2(int i) 
    { 
     return new MyClass2 { MyProperty = i.ToString() }; 
    } 
} 

即使對象不共享一個通用的接口,你應該能夠正確地寫一個IEqualityComparer<object>與兩個工作,例如如果你的拉姆達謂詞會一直:

(TypeA a, TypeB b) => a.PropA == b.PropB 

那麼你的類將是:

public class MyOtherEqualityComparer : IEqualityComparer<object> 
{ 
    private object GetProperty(object obj) 
    { 
     if (obj is TypeA) 
      return ((TypeA)obj).PropA; 
     else if (obj is TypeB) 
      return ((TypeB)obj).PropB; 
     else 
      throw new Exception(); 
    } 
    public bool Equals(object a, object b) 
    { 
     return GetProperty(a).Equals(GetProperty(b)); 
    } 
    public int GetHashCode(object obj) 
    { 
     return GetProperty(obj).GetHashCode(); 
    } 
} 
+0

感謝您抽出時間,我會很好地利用這個:)最後一件事:你能想到一個比「CrossRemove」更好的名字,因爲它不會說太多,英文是不是我的母語;) – Adassko

+1

有幾個名字可以使用:'差異','補充'或'減法'(來自[集合的數學思想](http://mathworld.wolfram.com/SetDifference)。 ),或'RemoveAll'像'List '的方法(除了需要一個謂詞,而不是一個集合)或'RemoveWhere''就像'HashSet ''的方法(它也需要一個謂詞)。我想我會用'Subtract'或'RemoveAll'去。 –

0

我認爲要做到這一點最簡單的方法是List<T>RemoveAll功能的等效,因爲它更一般。取而代之的

first.CrossRemove(second, (x, y) => x == y.ToString()); 

我會寫

first.RemoveAll(item1 => second.Any(item2 => item1 == item2.ToString())); 

不幸的是,ObservableCollection<T>沒有這個方法,所以我們需要寫一個:

public static class Extensions 
{ 
    public static void RemoveAll<T>(this ICollection<T> collection, Func<T, bool> pred) 
    { 
     var toBeRemoved = collection.Where(pred).ToArray(); 
     foreach (var item in toBeRemoved) 
      collection.Remove(item); 
    } 
} 

編輯:

以上擴展方法效率很低,其他算法如this one算得很多 更快。但在這種情況下,我認爲這並不重要,因爲我們正在討論大概與觀點相關的ObservableCollection<T>。鑑於此,我們應該只做很少的更改,否則佈局和重新渲染成本會非常高。如果您正在進行大量更改,那麼您應該用新的更換集合,以便佈局僅重新計算一次。