У меня есть список объектов, который имеет некоторые свойства.
class Accounts
{
long id;
CString account;
CTime start;
CTime end;
};
Чтобы показать это лучше, это выглядит примерно так:
ID Account Start End
-----------------------------------------
1 Bob 23-Jun-20 23-Jun-20
2 Sally 23-Jun-20 23-Jun-20
3 Mike 23-Nov-20 29-Nov-20
4 Sally 20-Dec-20 25-Dec-20
Мне нужно получить идентификаторы записей списка старше 4 месяцев (с этого момента). Но если на Аккаунте есть запись не старше 4-х месяцев, то она не подлежит возврату.
Например, элемент с идентификатором 1 должен быть возвращен, поскольку он старше 4 месяцев и не имеет экземпляров в дальнейшем списке. Предмет с идентификатором 2 не следует возвращать, поскольку он повторяется в экземпляре, которому меньше 4 месяцев (предмет с идентификатором 4). И, конечно же, товар с ID 3 не должен быть возвращен, потому что ему не исполнилось 4 месяца.
Моя идея состоит в том, чтобы дважды зациклить список и проверить, повторяется ли учетная запись. Затем сравнить дату и в соответствии с этим возвращаемым значением в другом списке.
std::list<Accounts> accountsList;
std::list<long> expiredAccounts;
CTime ctNow = CTime::GetCurrentTime();
for(auto &it1 : accountsList)
{
for(auto &it2 : cServiceNumberDetails)
{
CTimeSpan ts = ctNow - it.start;
long long tsDays = ts.GetDays(); //get number of day difference
CString account = it1.account;
if ((tsDays > 120) && it2.account == account && it1.start < it2.start)
{
expiredAccounts.push_back(it1.id);
}
}
}
Это может сработать (я не уверен), но есть ли более эффективный способ сделать это, потому что у меня может быть список с сотнями тысяч элементов, и двойной цикл по нему, вероятно, не лучшее решение?
Я бы предложил хранить список, отсортированный по дате, вставляя в список с помощью бинарного поиска.
Если под словом «не повторяться» вы подразумеваете, что все поля должны быть уникальными, то вы можете начать со старой стороны, проверяя элементы с одинаковой датой на наличие дубликатов. Как только вы доберетесь до элементов, которым меньше 4 месяцев, перестаньте проверять, хотите ли вы удалить старые элементы из списка.
В этом случае для выполнения этой проверки требуется только один цикл.
Редактировать: на самом деле я беру это обратно ... двоичный поиск не так хорошо работает со списками. Но, тем не менее, можно пройтись по списку и добавить его в правильное место, возможно, используя список пропуска, чтобы быстрее перейти в нужное место.
В одиночном цикле вы можете переупорядочить свои данные, чтобы узнать, какая учетная запись активна/неактивна. Также расположите все идентификаторы в списке для одной и той же учетной записи.
Пример ниже (is_active
— это просто функция или логика для определения того, что учетная запись активна и срок ее действия не истек, например: start < 120 в вашем случае):
std::map<string, bool> accountStatus;
std::map<string, std::list<long>> idsForAccount;
for (const auto& it : accountsList)
{
accountStatus[it.account] = accountStatus[it.account] or is_active(it);
idsForAccount[it.account].push_back(it.id);
}
Теперь в другом цикле извлеките все идентификаторы учетных записей, если срок действия учетной записи истек.
std::list<long> expiredAccounts;
for (const auto& it : accountStatus)
{
if (not it.second) // If account is not active add all ID
{
expiredAccounts.assign(idsForAccount[it.first].begin(), idsForAccount[it.first].end());
}
}
этот оператор находится на карте с именем accountStatus.
Я думаю, что это не сработает, потому что вы не можете использовать [] в экземпляре класса. Как и в первом цикле:
accountStatus[it.account]
.. но спасибо за помощь