C# 在c中重复where()与多个集合#

C# 在c中重复where()与多个集合#,c#,performance,coding-style,C#,Performance,Coding Style,我收集了一批物品a。每个A都有一个字段,该字段将is与一个对象B关联,我有另一个对象B的集合。换句话说,每个B都附加到As集合的子集(但仅在概念上,而不是在代码中)。该字段(关联A和B)在系统寿命期间可能会发生变化。存在防止更改此结构的系统要求 如果我需要对每个B的A集合重复执行操作,那么最好对A集合重复使用Where()方法,或者创建B拥有的另一个集合和管理相关项的添加和删除的类 让我看看是否可以在代码中捕捉到这一点: class A { public B owner;

我收集了一批物品a。每个A都有一个字段,该字段将is与一个对象B关联,我有另一个对象B的集合。换句话说,每个B都附加到As集合的子集(但仅在概念上,而不是在代码中)。该字段(关联A和B)在系统寿命期间可能会发生变化。存在防止更改此结构的系统要求

如果我需要对每个B的A集合重复执行操作,那么最好对A集合重复使用Where()方法,或者创建B拥有的另一个集合和管理相关项的添加和删除的类

让我看看是否可以在代码中捕捉到这一点:

    class A {
      public B owner;
      ...
    }

    class B {
      ...
    }

    class FrequentlyCalledAction {
      public DoYourThing(B current) {
        List<A> relevantItems = listOfAllAItems.Where(x => x.owner == current).ToList()
        foreach (A item in relevantItems) {
          ...
        }
      }
    }
A类{
公共房屋业主;
...
}
B类{
...
}
类频化{
公共事务(B当前){
ListRelevantItems=listOfAllAItems.Where(x=>x.owner==current).ToList()
foreach(相关项目中的项目){
...
}
}
}
Vs:

A类{
公共房屋业主;
...
}
B类{
公共物品清单;
}
类频化{
公共物品(B当前){
foreach(当前.itsItems中的项目){
...
}
}
}
类管理员{
公共项(A项、B项从、B项到){
from.itsItems.remove(项目);
至。ITS项目。添加(项目);
}
}

事实上,这一切都取决于你收藏的数量。Sol 2更复杂,但对于大的收集速度更快,而Sol 1对于不到100/1000的物品可能非常快。

这主要取决于集合的大小。如果只有几个项目,那么解决方案二带来的开销将大于性能增益

在本例中,我将使用解决方案一,因为它具有更好的可读性,并且管理起来不那么复杂

如果集合中有数千个项目,我会选择解决方案二。
moveItems
方法是一个O(n)操作,但在您的场景中,读操作似乎多于写操作。因此,您可以通过更结构化的设计获得更高的性能。

因为集合很小(~100项),而且它们经常变化(~4次迭代一次),所以请执行此操作,然后查看您是否有问题

public DoYourThing(B current)
{
    foreach(A item in listOfAllAItems.Where(a => a.owner == current))
    {
        ...
    }
}
我认为把IEnumerable转换成IList没有任何意义


如果这会给您带来性能问题,我不认为
AManager
是最佳答案,尽管这可能取决于关系的变化程度

如果您选择解决方案2,可能值得使用哈希集而不是列表。哈希集是O(1)表示添加和删除,而列表是O(1)表示添加,O(n)表示删除

另一个选择是这样做,其优点是A&B的用户不需要记住使用
AManager

static class GlobalDictionary
{
  private static Dictionary<B,HashSet<A>> dictionary = new Dictionary<B,HashSet<A>>();

  public static HashSet<A> this[B obj]
  {
    // You could remove the set and have it check to see if a Set exists for a B
    // if not you would create it.
    get {return dictionary[obj];}
    set {dictionary[obj] = value;}
  }
} 


class A 
{
  private B owner;  
  public B Owner
  {
    get{ return owner;}
    set
    {
      if (owner != null) GlobalDictionary[owner].Remove(this);

      owner = value;
      GlobalDictionary[owner].Add(this);
    }
  }
}

class B
{
  public B()
  {
    GlobalDictionary[this] = new HashSet<A>();
  }

  public IEnumerable<A> Children
  {
    get
    {
      return GlobalDictionary[this];
    }
  }
}
静态类全局字典
{
私有静态字典Dictionary=新字典();
公共静态哈希设置此[B obj]
{
//您可以删除该集合,并让它检查a B是否存在集合
//如果不是,你会创造它。
获取{返回字典[obj];}
set{dictionary[obj]=value;}
}
} 
甲级
{
私人楼宇业主;
公共房屋业主
{
获取{返回所有者;}
设置
{
如果(owner!=null)全局索引[owner]。删除(此);
所有者=价值;
GlobalDictionary[owner]。添加(此);
}
}
}
B类
{
公共图书馆B()
{
GlobalDictionary[this]=新的HashSet();
}
可数儿童的公共教育
{
得到
{
返回GlobalDictionary[此];
}
}
}

我还没有尝试过这个,所以可能需要一些调整,但你应该了解这个想法。

你多久做一次?A->B关系多久改变一次?As和Bs的集合有多大?B不能引用a吗?DoYourThing是系统中最频繁的调用之一。A->B关系可能每4次DoYourThing呼叫改变一次。它们都是小套间——可能是50B,也可能是100A。A需要多久知道它的主人是谁?您能否将A存储在其所有者的身上,并在需要时确定其所有者是谁?系统的其他部分需要A知道其所有者。您最终决定做什么?解决方案2的空间使用是否存在缺陷?这有关系吗,因为它们都只是参考资料?性能的提高是否超过了它?这同样取决于收集的大小,但实际上,列表中只存储引用。您可能需要考虑如何在没有其他引用的情况下从全局字典中删除B,以便垃圾收集器可以处理它们。您可以将MoveItems改进为O(1)我认为通过使用hashset。
static class GlobalDictionary
{
  private static Dictionary<B,HashSet<A>> dictionary = new Dictionary<B,HashSet<A>>();

  public static HashSet<A> this[B obj]
  {
    // You could remove the set and have it check to see if a Set exists for a B
    // if not you would create it.
    get {return dictionary[obj];}
    set {dictionary[obj] = value;}
  }
} 


class A 
{
  private B owner;  
  public B Owner
  {
    get{ return owner;}
    set
    {
      if (owner != null) GlobalDictionary[owner].Remove(this);

      owner = value;
      GlobalDictionary[owner].Add(this);
    }
  }
}

class B
{
  public B()
  {
    GlobalDictionary[this] = new HashSet<A>();
  }

  public IEnumerable<A> Children
  {
    get
    {
      return GlobalDictionary[this];
    }
  }
}