C#集合性能:是Hashset <string>和Dictionary <string,ilist <int =“”>&gt;为此目的最快的收藏?

时间:2016-08-17 08:53:29

标签: c# performance list collections hashset

我已经解析了一个Excel数据网格并构建了一个对象模型。有32列和100,000行。我被要求检查具有重复数据的行并报告它们。对于我的实现,我正在做以下事情:

  1. 使用任务我正在构建一个带有行ID和连接单元格内容的元组数组。
  2. 我遍历结果数组并使用HashSet,我尝试将连接值插入HashSet:
  3. 如果HashSet.Add()通过,我在我的词典中创建一个新条目&gt;结果集。
  4. 如果HashSet.Add()失败,我将该行ID添加到我的词典中的现有条目&gt;结果集
  5. 步骤1需要0.09秒,而剩下的需要花费822秒来处理:/有没有人可以通过更合适的集合或算法来确定我可以在哪里切断?

    代码如下:

    var results = new Dictionary<string, IList<int>>(numberOfRows);
    var hashSet = new HashSet<string>();
    var duplicateErrors = new List<string>();
    
    for (var row = firstRow; row <= lastRow; row++)
    {
        var row1 = row;
        taskArray[count++] =
        Task<Tuple<int, string>>.Factory.StartNew(() => GetCompleteRowData(row1, tableRawDataHolders));
    }
    
    foreach (var task in taskArray)
    {
        if (hashSet.Add(task.Result.Item2))
        {
            results.Add(task.Result.Item2, new List<int>() { task.Result.Item1 });
        }
        else
        {
            results[task.Result.Item2].Add(task.Result.Item1);
        }
    }
    

    public Tuple<int, string> GetCompleteRowData(int row, IEnumerable<ITableRawDataHolder> tableRawDataHolders)
        {
            return new Tuple<int, string>(row, string.Join("",
                tableRawDataHolders.Where(c => c.Row == row).Select(c => c.Value).ToArray()));
        }
    

    public class TableRawDataHolder : ITableRawDataHolder
    {
        public int Row { get; }
        public int Column { get; }
        public string Value { get; }
    
        public TableRawDataHolder(int row, int column, string value)
        {
            Row = row;
            Column = column;
            Value = value;
        }
    }
    

1 个答案:

答案 0 :(得分:2)

在这种情况下,问题不在于Dictionary或Hashset性能。

开销来自您在GetCompleteRowData中读取数据并处理任务的方式。

  • 每次需要转换下一条记录时,您似乎都会枚举完整的集合。
  • 对于每个下一条记录,您创建一个本身会增加一些小开销的任务。在任务结束之前,只需在使用task.Result时等待。
  • 还不清楚ITableRawDataHolder返回数据的速度有多快。

为了演示纯哈希集/字典性能,我创建了测试,其中迭代已经准备好的元组数组。这段代码在我的机器上只需32毫秒(i7四核)。

const Int32 numberOfRows = 200000;
var inputData = GetInputData(numberOfRows);
var results = new Dictionary<string, IList<int>>(numberOfRows);
var hashSet = new HashSet<string>();

var sw = Stopwatch.StartNew();
foreach (var dataItem in inputData)
{
    if (hashSet.Add(dataItem.Item2))
    {
        results.Add(dataItem.Item2, new List<int>() {dataItem.Item1});
    }
    else
    {
        results[dataItem.Item2].Add(dataItem.Item1);
    }
}
Console.WriteLine(sw.ElapsedMilliseconds);

以下是我如何生成测试数据(包括一些实际的重复数据)

private static List<Tuple<int, String>> GetInputData (int numberOfRows)
{
    var result = new List<Tuple<int, String>>(numberOfRows);
    var rnd = new Random();
    for (var i = 0; i < numberOfRows; i++)
    {
        // Once in 100 records we'll have not unique value
        if (result.Count > 0 && rnd.Next(100)%1 == 0)
        {
            result.Add(new Tuple<int, string>(i,  result[rnd.Next(result.Count)].Item2));
        }
        else
            result.Add(new Tuple<int, string>(i, Guid.NewGuid().ToString()));
    }
    return result;
}