使用C#字典解析日志文件

使用C#字典解析日志文件,c#,dictionary,C#,Dictionary,我试图解析一个相当长的日志文件,并创建一个更好、更易于管理的问题列表 我能够逐行读取和解析单个日志,但我需要做的是只显示唯一的条目,因为某些错误比其他错误更频繁,并且总是用相同的文本记录 我要做的是创建一个Dictionary对象来保存每个唯一的条目,当我处理日志文件时,搜索Dictionary对象以查看是否已经存在相同的值 这里是我所拥有的代码的一个粗略示例(一个正在进行的工作,我希望我所有的语法都正确),但它不起作用。由于某些原因,此脚本从未看到任何不同的条目(如果语句从未通过): 二线

我试图解析一个相当长的日志文件,并创建一个更好、更易于管理的问题列表

我能够逐行读取和解析单个日志,但我需要做的是只显示唯一的条目,因为某些错误比其他错误更频繁,并且总是用相同的文本记录

我要做的是创建一个Dictionary对象来保存每个唯一的条目,当我处理日志文件时,搜索Dictionary对象以查看是否已经存在相同的值

这里是我所拥有的代码的一个粗略示例(一个正在进行的工作,我希望我所有的语法都正确),但它不起作用。由于某些原因,此脚本从未看到任何不同的条目(如果语句从未通过):

二线

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

    rowdta[0]="ErrorType";
    rowdta[1]="Undefined variable: fvmsg";
    rowdta[2]="/url/processes.svc.php";
    rowdta[3]="Line Number 787";
因此,有了这个,字典将有两个条目,第一行和第三行

我还尝试了以下方法,nalso在日志文件文本中没有发现任何变化

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

有人能帮我弄清楚这个语法吗?我只是一个C#的新手,但这应该相对简单。和往常一样,我认为这应该是足够的信息来开始对话。如果您想要/需要更多详细信息,请告诉我。

您看到问题的原因是字符串数组不能用作字典中的键,而必须提供自定义或在其周围编写包装

编辑以下是自定义比较器的快速而肮脏的实现:

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());
    }
}
私有类阵列Q:IEqualityComparer{
公共布尔等于(T[]x,T[]y){
返回x.x(y);
}
public int GetHashCode(T[]obj){
返回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" }]);
vardd=newdictionary(newarrayeq());
dd[new[]{“a”,“b”}]=0;
dd[新[]{“a”,“b”}]+;
dd[新[]{“a”,“b”}]+;
Console.WriteLine(dd[new[]{“a”,“b”}]);

问题在于数组相等是引用相等。换句话说,它不依赖于数组中存储的值,它只依赖于数组的标识

一些解决方案

  • 使用
    Tuple
    保存行数据
  • 使用匿名类型保存行数据
  • 创建一个自定义类型来保存行数据,如果是类,则重写Equals和GetHashCode
  • 创建IEqualityComparer的自定义实现,以根据数组的值比较数组,并在创建字典时将其传递给字典

或者为实现的字符串创建一个包装器

public类LogFileEntry:IEquatable
{
私有只读字符串[]\u行;
公共LogFileEntry(字符串[]行)
{
_行=行;
}
公共覆盖int GetHashCode()
{
返回

_行[0]。GetHashCode()您可以在填充rowdta的位置发布代码吗?请尝试使用hashset而不是字典(因为您似乎不再需要这些值)。此外,请尝试使用.Equals()代替==比较字符串。感谢大家的帮助。我将尝试各种迭代,然后更新有效的方法。@phoog绝对!感谢您捕获它。我对Equals和GetHashCode的实现有点粗糙,准备就绪。您显然需要进行一些错误检查,并可能提供更好的哈希代码。+1.Al因此,使对象具有有意义的属性而不仅仅是行数组将有助于提高可读性(并可能节省一些内存,例如,行[3]看起来像整数行号)。这似乎可行,但我仍然遇到两个问题:1-由于logFileEntry是一个数组,因此Sum(o=>o.GetHashCode());无效。此外,它似乎没有像我预期的那样查找唯一值。我不确定是什么问题,因为调试器不会在Equals(..)函数中中断。我尝试中断到d.ContainsKey(条目)但它不会。有什么想法吗?我的坏主意,应该实现IEquatable并覆盖GetHashCode。非常感谢!我最初对此有问题,直到我意识到我的项目属性设置不正确。一旦我将其初始化为.NET 4项目,并添加对system.linq的引用,所有这些都很好地工作了!再次感谢!
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" }]);
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;
}
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;
}