Использование словаря C # для разбора файла журнала - PullRequest
0 голосов
/ 27 марта 2012

Я пытаюсь проанализировать довольно длинный файл журнала и создать более удобный список проблем.

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

Я собирался попытаться создать объект Dictionary, содержащий каждую уникальную запись, и, пока я работаю с файлом журнала, поискать в объекте Dictionary, чтобы увидеть, есть ли там те же значения.

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

    string[] rowdta = new string[4];
    Dictionary<string[], int> dict = new Dictionary<string[], int>();
    int ctr = -1;
    if (linectr == 1)
        {
            ctr++;
            dict.Add(rowdta, ctr);
        }
        else
        {
            foreach (KeyValuePair<string[], int> pair in dict)
            {
                if ((pair.Key[1] != rowdta[1]) || (pair.Key[2] != rowdta[2])| (pair.Key[3] != rowdta[3]))
                {
                    ctr++;
                    dict.Add(rowdta, ctr);
                }
            }
        }

Некоторые примеры данных: Первая строка

    rowdta[0]="ErrorType";
    rowdta[1]="Undefined offset: 0";
    rowdta[2]="/url/routesDisplay2.svc.php";
    rowdta[3]="Line Number 5";

2-я строка

    rowdta[0]="ErrorType";
    rowdta[1]="Undefined offset: 0";
    rowdta[2]="/url/routesDisplay2.svc.php";
    rowdta[3]="Line Number 5";

3-я строка

    rowdta[0]="ErrorType";
    rowdta[1]="Undefined variable: fvmsg";
    rowdta[2]="/url/processes.svc.php";
    rowdta[3]="Line Number 787";

Итак, в этом словаре будет 2 предмета: первая и третья.

Я также пробовал это со следующим, что nalso не находит никаких изменений в тексте файла журнала.

    if (!dict.ContainsKey(rowdta)) {}

Может кто-нибудь помочь мне понять этот синтаксис правильно? Я просто новичок в C #, но это должно быть относительно просто. Как всегда, я думаю, что этой информации должно быть достаточно, чтобы начать разговор. Если вы хотите / хотите более подробно, пожалуйста, дайте мне знать.

Ответы [ 3 ]

1 голос
/ 27 марта 2012

Либо создайте оболочку для ваших строк, которая реализует IEquatable .

public class LogFileEntry :IEquatable<LogFileEntry>
{
    private readonly string[] _rows;

    public LogFileEntry(string[] rows)
    {
        _rows = rows;
    }

    public override int GetHashCode()
    {
        return 
            _rows[0].GetHashCode() << 3 | 
            _rows[2].GetHashCode() << 2 | 
            _rows[1].GetHashCode() << 1 | 
            _rows[0].GetHashCode();
    }

    #region Implementation of IEquatable<LogFileEntry>

    public override bool Equals(Object obj)
    {
        if (obj == null) 
            return base.Equals(obj);

        return Equals(obj as LogFileEntry);  
    } 

    public bool Equals(LogFileEntry other)
    {
        if(other == null) 
            return false;

        return _rows.SequenceEqual(other._rows);
    }

    #endregion
}

Затем используйте это в своем словаре:

var d = new Dictionary<LogFileEntry, int>();

var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
    d[entry] ++;
} 
else
{
    d[entry] = 1;
}

Или создайте пользовательский компаратор, аналогичный предложенному @dasblinkenlight, и используйте его следующим образом

public class LogFileEntry 
{
}

public class LogFileEntryComparer : IEqualityComparer<LogFileEntry>{ ... }

var d = new Dictionary<LogFileEntry, int>(new LogFileEntryComparer());

var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
    d[entry] ++;
} 
else
{
    d[entry] = 1;
}
1 голос
/ 27 марта 2012

Причина, по которой вы видите проблему, состоит в том, что массив строк не может использоваться в качестве ключа в словаре без предоставления пользовательского IEqualityComparer<string[]> или написания обертки вокруг него.

РЕДАКТИРОВАТЬ Вот быстрая и грязная реализация пользовательского компаратора:

private class ArrayEq<T> : IEqualityComparer<T[]> {
    public bool Equals(T[] x, T[] y) {
        return x.SequenceEqual(y);
    }
    public int GetHashCode(T[] obj) {
        return obj.Sum(o => o.GetHashCode());
    }
}

Вот как вы можете его использовать:

var dd = new Dictionary<string[], int>(new ArrayEq<string>());
dd[new[] { "a", "b" }] = 0;
dd[new[] { "a", "b" }]++;
dd[new[] { "a", "b" }]++;
Console.WriteLine(dd[new[] { "a", "b" }]);
0 голосов
/ 27 марта 2012

Проблема в том, что равенство массивов - это равенство ссылок. Другими словами, он не зависит от значений, хранящихся в массиве, он зависит только от идентичности массива.

Некоторые решения

  • используйте Tuple для хранения данных строки
  • использовать анонимный тип для хранения данных строки
  • создайте пользовательский тип для хранения данных строки и, если это класс, переопределите Equals и GetHashCode.
  • создайте пользовательскую реализацию IEqualityComparer для сравнения массивов в соответствии с их значениями и передайте их в словарь при его создании.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...