【问题标题】:Most efficient way to select a specific object type in Dictionary and delete it在 Dictionary 中选择特定对象类型并将其删除的最有效方法
【发布时间】:2009-06-30 15:23:06
【问题描述】:

好的,我有一系列基于基类的对象,这些对象随机存储在 Dictionary 对象中。例如

class TypeA
{
   public int SomeNumber {get; set;}
   public void SomeFunction()
}

class TypeB : TypeA
{
   public string SomeString {get; set;}
}

class TypeC : TypeA
{
   public bool StuffReady()
}


Dictionary listOfClasses <long, TypeA>;

键值是已放入字典的对象数量的运行计数。它与当前字典计数不匹配。

我希望找到一个 TypeB 的对象,它的 SomeString == "123" 说,并删除它。 最好的方法是什么?

【问题讨论】:

    标签: c# linq collections


    【解决方案1】:

    如果您确定只有一个匹配的对象(或者如果您只想删除第一个匹配项):

    var found = listOfClasses.FirstOrDefault
        (
            x => (x.Value is TypeB) && (((TypeB)x.Value).SomeString == "123")
        );
    
    if (found.Value != null)
    {
        listOfClasses.Remove(found.Key);
    }
    

    如果可能有多个匹配的对象并且您想将它们全部删除:

    var query = listOfClasses.Where
        (
            x => (x.Value is TypeB) && (((TypeB)x.Value).SomeString == "123")
        );
    
    // the ToArray() call is required to force eager evaluation of the query
    // otherwise the runtime will throw an InvalidOperationException and
    // complain that we're trying to modify the collection in mid-enumeration
    foreach (var found in query.ToArray())
    {
        listOfClasses.Remove(found.Key);
    }
    

    【讨论】:

    • 应该只有一个对象的 SomeString 值为“123”。我将使用相同或相似的代码来确保这一点。编译器不允许对 'found' 进行空检查,但如果 'found' 没有值,Remove 语句不会引发异常。
    • @ChrisBD:很好。如果存在 Key=0 的合法字典条目,则在未找到任何项目时调用 Remove 可能会导致问题(因为在未找到任何项目时 found.Key 的值将默认为 0)。我已经更新了代码,改为对 found.Value 进行空检查。
    • @Luke。好点,我不确定是否需要检查 found.Value,但我同意您对 Key 值可能为 0 的观察。
    【解决方案2】:

    TypeA 类和字典的键之间似乎没有映射。键是 long 类型,并且类上没有该类型的属性。因此,您必须搜索 KeyValuePair 实例的集合,这将使您可以直接访问密钥。

    试试下面的

    var found = listOfClasses
      .Where(p => p.Value.SomeString == "123").
      .Where(p => p.Value.GetType() == typeof(TypeB))
      .Single();
    listOfClasses.Remove(found.Key);
    

    【讨论】:

    • Thios 需要强制转换才能在编译通过之前访问属性 SomeString,但随后会在运行时引发异常 - 这与 IEnumerable 和 KeyValue 对有关。仍然让我这么想 +1。
    【解决方案3】:

    如果您从性能方面考虑,那么 for 循环是更好的选择,但如果您从代码的紧凑性或代码管理的角度来看,那么 LINQ 是最佳选择。

    【讨论】:

    • 我相信性能差异会非常非常小。
    • 在这种情况下,我怀疑 LINQ 查询和“foreach”循环之间的性能差异很小。 (与往常一样,如果性能是一个非常重要的问题,那么您应该进行分析/基准测试。)
    【解决方案4】:

    您需要在每个对象中存储运行长度。在TypeA 中添加一个属性,例如RunningLength。然后使用两个字典,一个用于存储TypeA 对象,另一个用于存储TypeB 对象。

    每当您创建一个对象(从TypeA 降序的任何类型)时,将其添加到第一个字典中。如果创建的对象是TypeB,则将其添加到第二个字典中:

    Dictionary listOfClasses <long, TypeA>;
    Dictionary listOfTypeBClasses <string, TypeB>;
    
    TypeA newOject = TypeAFactory.Create();
    
    if(newObject is TypeB)
    {
      TypeB objB = newObj as TypeB;
      listOfTypeBClasses[objB.SomeString] = objB;
    }
    

    使用 SomeString = "123" 移除 TypeB 的对象

    if(listOfTypeBClasses.ContainsKey("123"))
    {
      long keyA = listOfTypeBClasses["123"].RunningLength;
      listOfClasses.Remove(keyA);
      // if required remove the item from listOfTypeBClasses as well
      listOfTypeBClasses.Remove("123");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2010-09-05
      • 2019-02-01
      • 1970-01-01
      • 2014-03-14
      相关资源
      最近更新 更多