Как удалить повторяющиеся элементы из очереди в течение определенного периода времени? - PullRequest
0 голосов
/ 09 февраля 2011

Я хотел бы эффективно удалить дубликаты записей из очереди. В очереди есть собственный класс с DateTime, FullPath и несколькими другими вещами

private Queue<MyCustomClass> SharedQueue;

DateTime в классе - это отметка времени при вставке в очередь. Я хотел бы использовать следующую логику: Удалить дубликаты из очереди, если FullPath идентичен в течение 4-секундного окна (то есть, если он добавлен в очередь в течение 4 секунд после дубликата полного пути). У меня есть события, которые я хочу посмотреть, но несколько дубликатов все равно появятся, и это нормально.

Я использую c # 2.0, класс FileSystemWatcher и рабочую очередь.

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

Или мне следует использовать глобальную частную переменную Dictionary ? Так я могу быстро найти его? или локальная копия очереди? Возможно, лучше всего ограничить локальную очередь до 100 элементов в случае большого количества файловых событий? Хотя в моем случае это «должно быть» только относительно небольшое количество файлов для мониторинга в папке ... но все всегда меняется ...

Спасибо за любую помощь.

: Изменить: 10 февраля 8:54 EST: Поэтому я решил реализовать хорошее простое решение, насколько я могу судить. Я не думаю, что слишком долго держусь за клавиши Dict ...

: Изменить: 10 февраля 9:53 EST: обновлено, поскольку мой словарь не может содержать повторяющиеся значения.

   public void QueueInput(HotSynchUnit.RcdFSWFile rcd)
// start the worker thread when program starts.
// call Terminate.Set() in the programs exit routine or close handler etc.
{
  // lock shared queue
  lock (SharedQueue)
  {
    if (!IsDuplicateQueueInput(rcd))  // only add unique values to queue
    {
      SharedQueue.Enqueue(rcd);
      SomethingToDo.Set();
    }
  }
} // public void QueueInput

private bool IsDuplicateQueueInput(HotSynchUnit.RcdFSWFile rcd)
/* Return true if the object is a duplicate object.
 * Pseudo Code:
 * 
 * isDuplicate = false
 * Lock Dictionary
 * -If lastTimeStamp > 4 seconds ago then       // Optimization: save lastTimeStamp
 *    if Dict.Count > 0 then clear Dictionary
 *    return isDuplicate
 * -If not Dict.TryGetValue(sPath, dtTimeStamp) then
 *    Dict.AddKey()
 * -Else
 *    Compare key timestamp to Currenttime
 *    if key timestamp is <= 4 seconds ago then
 *       IsDuplicate = True
 *
 *    Dict.RemoveKey()
 *    Dict.AddKey()
 * 
 * return isDuplicate
*/
{
  // put real code here
}

Ответы [ 4 ]

1 голос
/ 09 февраля 2011

Я только что подумал об использовании любой коллекции , аналогичной универсальной хеш-таблице ... Примерно так:

Dictionary<string, YourClass> dict = new Dictionary<string, YourClass>();

/// just let's assume you want to add/check for "c:\demo.txt"

if (!dict.ContainsKey(@"c:\demo.txt"))
{
   /// add items to dict by passing fullPath as key and your objects as value
   dict.add(@"c:\demo.txt", obj1);
} 
else if (dict[@"c:\demo.txt"].CheckForIntervall())
{
   /// replace current object in dictionary with new object - in case you want to..
   /// or just do what you want to 
}

edit - ваш пользовательский класс можетнекоторые функции, подобные этой:

class YOURCUSTOMCLASS
{
    private DateTime creationTime;

    public DateTime CreationTime
    { get { return creationTime; } }

    public YOURCUSTOMCLASS(parametersGoesHere xyz)
    {
          creationTime = DateTime.Now;
    }

    /// in this case this method will return true
    /// if the timeSpan between this object and otherObject
    /// is greater than 4 seconds
    public bool CheckForInterval(YOURCUSTOMCLASS otherObject)
    {
         TimeSpan diff = otherObj.CreationTime.Subtract(creationTime);

         /// you may replace 4 through any other digit, or even better take
         /// a const/global var/static ...
         return diff.TotalSeconds > 4;
    }

    /// all the other stuff you need ...
}

Конечно, вы потеряете функциональность очереди - но вы получите значительное увеличение времени выполнения , если ваша очередь содержитмного элементов.

hth

0 голосов
/ 09 февраля 2011

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

0 голосов
/ 09 февраля 2011

Я бы сделал класс-оболочку, а не выходил из очереди, поскольку пользователи базового типа Queue ожидают другого поведения. (Контракты на данные в .NET 4.0 могут даже жаловаться при этом.)

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

При снятии очереди вам необходимо проверить, содержит ли внутренняя очередь элементы, и в противном случае выбрать самый ранний элемент из словаря.

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

0 голосов
/ 09 февраля 2011

Я бы сделал подкласс:

class MyDeduplicatedQueue : Queue<MyCustomObject> {
    /// etc
}

Затем вы можете поместить всю соответствующую логику фильтрации в метод Enqueue.

...