Повторяется где () против нескольких коллекций в C # - PullRequest
4 голосов
/ 12 октября 2011

У меня есть коллекция объектов А. У каждого A есть поле, которое соотносится с объектом B - из которого у меня есть другая коллекция. Другими словами, каждый B связан с подмножеством набора As (но только концептуально, а не в коде). Это поле, связывающее А с В, может меняться в течение срока службы системы. Существуют системные требования, препятствующие изменению этой структуры.

Если мне нужно многократно выполнять операции над множеством A каждого B, было бы лучше повторно использовать метод Where () для коллекции A или создать другую коллекцию, которой владеет 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) {
          ...
        }
      }
    }

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);
      }
    }

Ответы [ 4 ]

1 голос
/ 12 октября 2011

Это в первую очередь зависит от размера наборов. Если имеется всего несколько элементов, накладные расходы, которые приходят с решением two , превышают прирост производительности.

В этом случае я бы использовал решение one , так как оно лучше читается и им сложнее управлять.

Если в наборе тысячи предметов, я бы выбрал решение two . Метод moveItems - это операция O (n), но в вашем сценарии больше операций чтения, чем записи. Поэтому вы получаете больше производительности благодаря более структурированному дизайну.

0 голосов
/ 12 октября 2011

Если вы выберете решение 2, возможно, стоит использовать HashSet, а не List.HashSet - O (1) для Add & Remove, тогда как List - O (1) для Add и 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];
    }
  }
}

Я не пробовал это, так что, вероятно, это потребует некоторых настроек, но вы должны понять.

0 голосов
/ 12 октября 2011

Поскольку наборы небольшие (~ 100 элементов) и они часто меняются (~ каждые 4 итерации), сделайте это, а затем посмотрите, есть ли у вас проблемы.

public DoYourThing(B current)
{
    foreach(A item in listOfAllAItems.Where(a => a.owner == current))
    {
        ...
    }
}

Не вижу смысла приводить IEnumrable к IList .

Если это создает проблемы с производительностью, я не думаю, что AManager - ваш лучший ответ, хотя это может зависеть от того, насколько сильно изменятся отношения.

0 голосов
/ 12 октября 2011

На самом деле все зависит от размера вашей коллекции.Sol 2 более сложный, но быстрее для большой коллекции, в то время как sol1 может быть очень быстрым для менее чем 100/1000 предметов или около того.

...