I've got a collection of object A's. Each A has a field that correlates is to an object B - of which I have another collection. In other words, each B is attached to a subset of the collection of As (but only 开发者_高级运维conceptually, not in code). This field - correlating A to B - can change during the life of the system. There are system requirements that prevent changing of this structure.
If I need to repeatedly perform operations on each B's set of A's, would it be better to repeated use the Where() method on the collection of A's or create another collection that B owns and a class that manages the add and remove of the relevant items.
Let me see if i can capture this in code:
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) {
...
}
}
}
Vs:
class A {
public B owner;
...
}
class B {
public List<A> itsItems;
}
class FrequentlyCalledAction {
public void DoYourThing(B current) {
foreach (A item in current.itsItems) {
...
}
}
}
class AManager {
public void moveItem(A item, B from, B to) {
from.itsItems.remove(item);
to.itsItems.add(item);
}
}
This primarily depends on the size of the sets. If there are only a few items the overhead that comes with the solution two is bigger than the performance gain.
In this case I would use solution one since it has a better readability and is less complicated to manage.
If there are thousands of items in the set I would go for solution two. The moveItems
method is an O(n) operation but it seems that there are more reads than writes in your scenario. Therefore you gain more performance through the more structured design.
In fact it all depend of the size of your collection. Sol 2 is more complex but faster for big collection while sol1 can be very fast for less than 100/1000 items or so.
Since the sets are small (~100 items) and they change often (~every 4 iterations) do this, then see if you have a problem.
public DoYourThing(B current)
{
foreach(A item in listOfAllAItems.Where(a => a.owner == current))
{
...
}
}
I don't see any point in casting the IEnumrable<A> to an IList<A>.
If this gives you a performance problem I don't think AManager
is your best answer, although this could depend on how much the relationships change.
If you go for solution 2 it might be worth using a HashSet rather than a List. A HashSet is O(1) for Add & Remove whereas a List is O(1) for Add and O(n) for remove.
Another option is this which has the advantage that users of A & B don't need to remember to use 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];
}
}
}
I haven't tried this so it's likely it'll require some tweaks but you should get the idea.
精彩评论