Наиболее эффективный способ хранения объектов с соответствующими индексами - PullRequest
3 голосов
/ 04 ноября 2019

Я хочу хранить коллекцию очков, которые являются объектами класса Point. (Point содержит свойства positionX, positionY, electricalPotential и т. Д.) Каждый из них должен иметь индекс i, но его не нужно упорядочивать каким-либо образом. Вот почему я использовал словарь Dictionary<int, Point> meshpoints в первую очередь.

Первый вопрос:
Является ли словарь наиболее эффективным способом хранения моих данных, если я только хочу сохранитьобъект с определенным индексом / ключом, особенно если речь идет о проблемах производительности, таких как добавление, поиск и цикл для каждого элемента?

Второй вопрос:
Если я хочу добавитьnew Point, как мне получить «следующий» бесплатный ключ? Например, если у меня есть словарь с хэш-ключами 0, 1, 2, 3 и 4, как мне получить 5 для следующего ключа элемента?

Вариант 1: meshpoints.Keys.Max() и meshpoints.Keys.Last() занимают много времени в моих тестах.

Dictionary<int, string> meshpoints = new Dictionary<int, string>();

meshpoints.Add(meshpoints.Keys.Max() + 1, "itemA");

meshpoints.Add(meshpoints.Keys.Max() + 1, "itemB");

Вариант 2: Создание отдельной переменной counter довольно быстро в моем тесте производительности, но действительно ли это самый элегантный способ? Я имею в виду, у вас всегда есть отдельное целочисленное значение со словарем для всех методов и т. Д. ...

Dictionary<int, string> meshpoints = new Dictionary<int, string>();
int counter = 0;

meshpoints.Add(counter, "itemA");
counter++;

meshpoints.Add(counter, "itemB");
counter++;

Опция 3: meshpoints.Count() не будет работать, когдаЯ также удаляю элементы в любой момент.

Ответы [ 3 ]

1 голос
/ 04 ноября 2019

Вам не нужен словарь, поскольку то, что вы хотите сделать, можно сделать с помощью списка.

Поскольку вы используете Count + 1 в качестве нового идентификатора, вы можете добавить автоматически сгенерированный идентификатор к классу Point, и он станет лучше:

public class Point
{ 
  static private int NextID;

  int ID { get; }
  public Point()
  {
    ID = NextID++;
  }
}

List<Point> meshPoints = new List<Point>();

var meshPointA = new Point();
var meshPointB = new Point();
var meshPointC = new Point();

meshPoints.Add(meshPointA);
meshPoints.Add(meshPointB);
meshPoints.Add(meshPointC);

var meshPoint = meshPoints.Where(p => p.ID == 2).SingleOrDefault();

При этом у вас никогда не будетДублируемый идентификатор и конфликты при добавлении, вставке и удалении объектов.

С параметром 1 Макс не обеспечивает быстродействие.

С параметром 3 использование счетчика вызовет следующие проблемы: если вы добавите 4 балла в следующемсначала удалите два, затем добавьте один, последний будет иметь идентификатор 3, в то время как два оставшихся имеют 3 и 4 в качестве идентификатора ... так что вариант 2. лучше.

Если вы хотите словарь, вы можете сделатьто же самое, создав класс, встраивающий внутренний словарь, имеющий NextID и предлагающий методы, которые вы хотите предоставить, такие как Add, Remove, ContainsX, ID (Items.Keys), Points (Items.Values) и т. д. (Все, что вы хотите, чтобы управлять этой специализированной коллекцией):

public class PointsDictionary : IEnumerable<Point>
{
  private readonly Dictionary<int, Point> Items = new Dictionary<int, Point>();

  private int NextID;

  public Point this[int index]
  {
    get { return Items.ContainsKey(index) ? Items[index] : null; }
    set { ... }
  }

  public Dictionary<int, Point>.KeyCollection IDs
  {
    get { return Items.Keys; }
  }

  public Dictionary<int, Point>.ValueCollection Points
  {
    get { return Items.Values; }
  }

  public int Add(Point point)
  {
    int index = NextID++;
    Items.Add(index, point);
    return index;
  }

  ...

}

Так что здесь, у вас будет сильный и чистый дизайн.

0 голосов
/ 06 ноября 2019

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

с определенным индексом / ключом,

, то ключ доступа должен быть известен инициатору доступа ... иначе почемукто-нибудь захочет использовать словарь с целыми числами в качестве ключа?

как мне получить "следующий" свободный ключ?

Один не гарантирован уникальность с Object.GetHashCode Method , и он должен быть переопределен вами для создания правильного хэша, но можно сделать что-то вроде этого

var myDict = new Dictionary<int, PointIt>();

var p1 = new PointIt() { PositionX=1, PositionY=2,  ElectricalPotential=999.99};
var p2 = new PointIt() { PositionX=1, PositionY=2,  ElectricalPotential=999.99};

myDict.Add(p1.GetHashCode(), p1);
myDict.Add(p2.GetHashCode(), p2);

myDict.ToList()
      .ForEach(itm => Console.WriteLine($"Key ({itm.Key}) Value {itm.Value}"));

С выводом, таким как

Key (23832771) Value X:1 Y:2 Potential:999.99
Key (44512918) Value X:1 Y:2 Potential:999.99

public class PointIt
{
    public int PositionX { get; set; }
    public int PositionY { get; set; }
    public double ElectricalPotential { get; set; }

    public override string ToString()
        => $"X:{PositionX} Y:{PositionY} Potential:{ElectricalPotential}";
}
0 голосов
/ 04 ноября 2019

Если вам не нравится иметь две отдельные переменные, то создайте новую структуру, чтобы связать их вместе:

struct MeshPointContainer
{
    private int _counter = 0;
    private List<Point> _pts = new List<Point>();

    public int Add(Point pt) {
        _pts.Add(pt);
        return ++counter;
    }
}

Затем используйте это следующим образом:

var meshPoints = new MeshPointContainer();
meshPoints.Add(new Point(-1f));

Это будетбыть немного сложнее, если вы хотите иметь возможность снимать очки, но пока вы не указали, что делаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...