Как хранить объекты для последующего использования и сделать их доступными для поиска - PullRequest
9 голосов
/ 05 декабря 2011

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

<i>What I'm doing</i>:                      <i>Example usage</i>:

image prototype

Проблема :

  1. Если я хочу получить определенную дату, мне нужно просмотреть все элементов в векторе, чтобы увидеть, совпадает ли RecPaymentsStack.stackDate с датой, запрошенной пользователем.
  2. На самом деле RecPaymentStackна данный момент совершенно бесполезен, потому что то, что я должен делать, - это при добавлении нового элемента проверять, был ли уже создан RecPaymentStack.stackDate для свойства Date нового элемента, и если это так, добавитьновый указатель на «RecPayments» на массив указателей внутри объекта «RecPaymentStack».Но как?

Я, вероятно, излишне усложняю вещи (чем-то, что я делаю много), поэтому объяснение того, как что-то вроде должно быть сделано, было бы очень приятно.

Подробная информация: (на случай, если я был слишком расплывчатым)

Предполагается, что приведенный ниже пример напоминает календарь, который может содержать определенные элементы (RecPayments), и эти элементы сгруппированыпо их дате (RecPaymentsStack).

struct RecPayments
{
    std::string name;
    Date* date;
    float cost;
};

struct RecPaymentsStack
{
    Date* stackDate; //This stack's date
    RecPayments * thePaymentItem; //Hold pointer to the actual item
};

И вот как я в настоящее время храню их

std::vector<RecPaymentsStack*> RecPaymentsVector; //This vector will hold pointers to all the Recurring Payments

void addRecurring(std::string theDate,std::string theName,float theCost)
{
    //New recurring payment
    RecPayments * newPaymentItem = new RecPayments;
    //Set recurring payment properties
    newPaymentItem->name = theName;
    newPaymentItem->date = new Date(stringToChar(theDate));
    newPaymentItem->cost = theCost;

    //Add recurring payment to stack
    RecPaymentsStack * addToStack = new RecPaymentsStack;
    addToStack->stackDate = new Date(stringToChar(theDate));
    addToStack->thePaymentItem = newPaymentItem;

    //Add pointer to RecPaymentsStack to vector
    RecPaymentsVector.push_back(addToStack);
}

Итак, чтобы получить элементы на определенную дату, я сейчас перехожу все указатели в векторе, чтобы увидеть, соответствует ли свойство stackDate запрошенной дате, и если да, то я использую свойство thePaymentItem, чтобы показать фактический элемент.

void getItemsNow(Date requestedDate)
{
    std::cout << "Showing Dates for " << requestedDate << std::endl;
    unsigned int i;
    for(i=0;i<RecPaymentsVector.size();i++) //Go over all items in vector
    {
        Date dateInVector(*RecPaymentsVector[i]->stackDate); //Get the date from the vector
        if(dateInVector == requestedDate) //See if Date matches what the user requested
        {
            //Date matched, show user the item properties.
            std::cout << "Date: " << dateInVector <<
                " has name: " << RecPaymentsVector[i]->thePaymentItem->name <<
                " and price " << RecPaymentsVector[i]->thePaymentItem->cost <<
                std::endl;
        }
    }
}

3 проблемыс этим:

  1. Перебирать все элементы в векторе крайне неэффективно, если мне нужна только пара указателей
  2. RecPaymentStack на самом деле совершенно бесполезен на данный момент, потому что я должен делать, то есть, при добавлении нового элемента, проверять, было ли уже создано «RecPaymentStack.stackDate» для свойства Date нового элемента, и если это так, добавить новый указатель на «RecPayments» в массив указателей внутри объекта "RecPaymentStack".Но как?
  3. Все это кажется чрезвычайно глупым для начала ... возможно, есть гораздо более простой / профессиональный способ сделать это, но я не могу понять, что, возможно, потому что я все еще думаю как PHPer.

Итак, общая идея здесь заключается в том, что я в конечном итоге делаю что-то вроде (глупый пример)

for each RecPaymentsStack->stackDate //For each unique Date, show it's children items.
{
    cout << "The Date is " CurrentRecPaymentsStack->stackDate and it holds the following items:
    for each CurrentRecPaymentsStack->thePaymentItem //This would now be an array of pointers
    {
        cout << "item name " CurrentRecPaymentsStack->thePaymentItem->name << " with cost " << CurrentRecPaymentsStack->thePaymentItem->cost << endl;
    }
}

, что в основном охватывает все уникальные объекты RecPaymentsStack (уникальныеопределяется его свойством «Date»), и для каждой даты он будет отображать «детей» из структуры RecPayments.

И должен быть какой-то способ поиска конкретной даты без необходимости перебора все доступные.

Ответы [ 2 ]

2 голосов
/ 05 декабря 2011

Вместо того, чтобы использовать вектор для управления вашими предметами, вы должны заменить ваш RecPaymentsStack экземпляр на std::multimap.Тип ключа - ваша Date структура, тип значения - RecPayments (который я бы изменил на единственную форму RecPayment).Небольшой пример (не проверено):

typedef std::multimap<Date, RecPayment> RecPaymentsByDateMap;
typedef std::pair<RecPaymentsByDateMap::iterator, 
                  RecPaymentsByDateMap::iterator>
                                        RecPaymentsByDateMapIters;

RecPaymentsByDateMap payments_by_date;

RecPaymentsByDateMapIters findByDate(Date date) {
  return payments_by_date.equal_range(date);
}

...

// find all payments with the given date
RecPaymentsByDateMapIters iters = findByDate(...);
for (RecPaymentsByDateMap::iterator it = iters.first;
     it != iters.second;
     ++it)
{
  std::cout << "Payment " << it->second.name << std::endl;
}
1 голос
/ 05 декабря 2011

Я мог бы придумать это так - это просто бесполезная идея, детали должны быть скорректированы в соответствии с вашими требованиями:

#include <deque>
#include <map>
#include <string>

struct RecPayment
{
    std::string name;
    Date        date;
    float       cost;
};

struct RecPaymentsStack
{
    Date stackDate;
    std::deque<RecPayment> thePaymentItem;

    bool operator<(RecPaymentsStack const & rhs) const
    {
      return stackDate < rhs.stackDate;
    }

    explicit RecPaymentsStack(Date const & d) : stackDate(d) { }
};

typedef std::multimap<RecPaymentsStack> PaymentsCollection;

Теперь вы можете вставлять элементы:

PaymentsCollection payments;

{
  auto it = payments.emplace(Date("..."));
  it->thePaymentItem.emplace_back(Payment{name1, date1, cost1});
  it->thePaymentItem.emplace_back(Payment{name2, date2, cost2});
  it->thePaymentItem.emplace_back(Payment{name3, date3, cost3});
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...