如何将2个LINQ词典合并为1
本文关键字:合并 LINQ 2个 | 更新日期: 2023-09-27 18:19:31
我有两个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();
}
}
那么,使用所有这些逻辑,我该如何解决我的问题呢?
//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];
});
遍历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;
}
我相信你可以编写更简单的代码来实现同样的目标,但我已经找到了一种方法来减少你在第一个和第二个列表中迭代的次数。如果性能不是一个问题,那么一个更简单的方法可能是合适的,该方法只在duplispullList中搜索datapullList中的每个元素。
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:打包为一个类,在visualstudio中编写,因此不应该有任何语法错误。