如何将2个LINQ词典合并为1个?

时间:2012-01-06 05:58:46

标签: c# linq

我有2个excel文件,我已将其转换为列表。第一个文件包含我需要的所有项目的完整列表。但是,第二个列表中有一小部分需要在第一个列表中更改的项目。 以下是我的第一个列表的构建方式:

IEnumerable<ExcelRow> queryListA = from d in datapullList
                                          select new ExcelRow
                                           {
                                               Company = d.GetString(0),
                                               Location = d.GetString(1),
                                               ItemPrice = d.GetString(4),
                                               SQL_Ticker = d.GetString(15)
                                           };

第二个列表以非常类似的方式构建:

IEnumerable<ExcelRow> queryListB = from dupes in dupespullList
                                          select new ExcelRow
                                           {
                                               Company = d.GetString(0),
                                               Location = d.GetString(1),
                                               NewCompany = d.GetString(4)
                                           };

因此,如果第一个列表中的某个特定位置的公司与第二个列表匹配,那么该公司将更改为新公司名称。

然后,我的最终列表应该包含第一个列表中的所有内容,但是从第二个列表中指定了更改。

我几天来一直在努力解决这个问题。如果您需要更多详细信息,请与我们联系。

[更新:]我对LINQ和C#很新。我在网上找到了关于Office 2003 Excel阅读器的代码。如何从以下所有类创建1列表(如上所述)? 我的ExcelRow类:

class ExcelRow
{     
    List<object> columns;

    public ExcelRow()
    {
        columns = new List<object>();
    }

    internal void AddColumn(object value)
    {
        columns.Add(value);
    }

    public object this[int index]
    {
        get { return columns[index]; }
    }

    public string GetString(int index)
    {
        if (columns[index] is DBNull)
        {
            return null;
        }
        return columns[index].ToString();
    }

    public int Count
    {
        get { return this.columns.Count; }
    }
}

我的ExcelProvider类:

class ExcelProvider : IEnumerable<ExcelRow>
{
    private string sheetName;
    private string filePath;
    private string columnName1;
    private string columnName2;
    private List<ExcelRow> rows;

    public ExcelProvider()
    {
        rows = new List<ExcelRow>();
    }

    public static ExcelProvider Create(string filePath, string sheetName, string columnName1, string columnName2)
    {
        ExcelProvider provider = new ExcelProvider();
        provider.sheetName = sheetName;
        provider.filePath = filePath;
        provider.columnName1 = columnName1;
        provider.columnName2 = columnName2;
        return provider;
    }

    private void Load()
    {            
        string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=    ""Excel 8.0;HDR=YES;IMEX=1""";            
        connectionString = string.Format(connectionString, filePath);
        rows.Clear();
        using (OleDbConnection conn = new OleDbConnection(connectionString))
        {
            try
            {
                conn.Open();
                using (OleDbCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = string.Format("SELECT * FROM [{0}$] WHERE {1} IS NOT NULL AND {2} <> \"{3}\"", sheetName, columnName1, columnName2, null);
                    using (OleDbDataReader reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            ExcelRow newRow = new ExcelRow();
                            for (int count = 0; count < reader.FieldCount; count++)
                            {
                                newRow.AddColumn(reader[count]);
                            }
                            rows.Add(newRow);
                        }
                    }
                }
            }
            catch (Exception ex)
            { throw ex; }
            finally
            {
                if (conn.State == System.Data.ConnectionState.Open)
                    conn.Close();
            }
        }
    }

    public IEnumerator<ExcelRow> GetEnumerator()
    {
        Load();
        return rows.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        Load();
        return rows.GetEnumerator();
    }
}

所以,使用所有这些逻辑,我该如何解决我的问题?

3 个答案:

答案 0 :(得分:1)

//first create a dictionary of comapny whose name has been changed
   var dict = queryListB.ToDictionary(x => x.Company, y => y.NewCompany);

    //loop on the first list and do the changes in the first list
    queryListA.ForEach( x => 
                        {
                            if(dict.Keys.Contains(x.Company))
                                x.Company = dict[x.Company];
                        });

答案 1 :(得分:1)

循环遍历queryListA,查看queryListB中是否有匹配的公司。如果是,则更新Company属性。

以下是代码:

foreach (var companyA in queryListA)
{
  var companyBMatch = queryListB.FirstOrDefault(x => x.Company == companyA.Company && x.Location == companyA.Location);
  if (companyBMatch != null)
    companyA.Company = companyBMatch.NewCompany;
}

答案 2 :(得分:0)

我确信你可以编写更简单的代码来实现相同的目标,但我已经采用了一种方法来减少你必须迭代第一和第二个列表的次数。如果性能不是问题,那么只需在datapullList中为每个元素搜索dupespullList的简单方法就可能是合适的。

var excelRowCreator = new ExcelRowCreator(dupespullList);
var finalRows = excelRowCreator.CreateExcelRows(datapullList);

// ...

public class ExcelRowCreator
{
    /// <summary>
    /// First key is company name, second is location 
    /// and final value is the replacement name.
    /// </summary>
    private readonly IDictionary<string, IDictionary<string, string>> nameReplacements;

    /// <summary>
    /// I don't know what type of objects your initial 
    /// lists contain so replace T with the correct type.
    /// </summary>
    public ExcelRowCreator(IEnumerable<T> replacementRows)
    {
        nameReplacements = CreateReplacementDictionary(replacementRows);
    }

    /// <summary>
    /// Creates ExcelRows by replacing company name where appropriate.
    /// </summary>
    public IEnumerable<ExcelRow> CreateExcelRows(IEnumerable<T> inputRows)
    {
        // ToList is here so that if you iterate over the collection 
        // multiple times it doesn't create new excel rows each time
        return inputRows.Select(CreateExcelRow).ToList();
    }

    /// <summary>
    /// Creates an excel row from the input data replacing
    /// the company name if required.
    /// </summary>
    private ExcelRow CreateExcelRow(T data)
    {
        var name = data.GetString(0);
        var location = data.GetString(1);

        IDictionary<string, string> replacementDictionary;
        if (nameReplacements.TryGetValue(name, out replacementDictionary))
        {
            string replacementName;
            if (replacementDictionary.TryGetValue(location, out replacementName))
            {
                name = replacementName;
            }
        }

        return new ExcelRow
        {
            Company = name,
            Location = location,
            ItemPrice = data.GetString(4),
            SQL_Ticker = data.GetString(15)
        };
    } 

    /// <summary>
    /// A helper method to create the replacement dictionary.
    /// </summary>
    private static IDictionary<string, IDictionary<string, string>> CreateReplacementDictionary(IEnumerable<T> replacementRows)
    {
        var replacementDictionary = new Dictionary<string, IDictionary<string, string>>();
        foreach (var dupe in replacementRows)
        {
            var name = dupe.GetString(0);
            IDictionary<string, string> locationReplacements;
            if (!replacementDictionary.TryGetValue(name, out locationReplacements))
            {
                locationReplacements = new Dictionary<string, string>();
                replacementDictionary[name] = locationReplacements;
            }

            locationReplacements[dupe.GetString(1)] = dupe.GetString(4);
        }

        return replacementDictionary;
    }
}

UPDATE :打包成一个类并在visual studio中编写,因此不应该有任何语法错误。