C# 当两个字典的值在C中相等时,在列表中合并/添加字典#
我想从原始列表字典值(C# 当两个字典的值在C中相等时,在列表中合并/添加字典#,c#,dictionary,C#,Dictionary,我想从原始列表字典值(list)中提取一个已处理的字典值列表(list) 原始dict可能包含字符串/数值 例如: Dictionary rawListDict=newdictionary(); 添加(“产品”、“苹果”); 添加(“地区”、“西部”); 添加(“利润”,90); 原始列表: 苹果西90 苹果东10 苹果西80 已处理列表: 苹果西170 苹果东10 考虑一个有相同产品和地区的词典的列表,我想要一个单独的dict,当“产品”和“地区”相同时,添加“利润”。(即)具有类似项的词典
list
)中提取一个已处理的字典值列表(list
)
原始dict可能包含字符串/数值
例如:
Dictionary rawListDict=newdictionary();
添加(“产品”、“苹果”);
添加(“地区”、“西部”);
添加(“利润”,90);
原始列表:
苹果西90
苹果东10
苹果西80
已处理列表:
苹果西170
苹果东10
考虑一个有相同产品和地区的词典的列表,我想要一个单独的dict,当“产品”和“地区”相同时,添加“利润”。(即)具有类似项的词典列表,分组为单个词典,没有任何副本
注意:原始列表可以增长到超过30K个条目:-(
我用蛮力技术实现了一个逻辑,它消耗了大量的内存和时间。有没有办法用LINQ风格或者其他方法来减少时间和内存
编辑:我更喜欢字典,因为只有在运行时才知道成员/键的数量。
我实施的代码:
//Get fields which could be used for combining values
var nonMeasurableFields = report.datagrid_fields.
Where(field => field.dataType.Equals(ImFieldDatatype.STRING_VALUE) || field.dataType.Equals(ImFieldDatatype.DATE_VALUE)).
Select(field => field.name).ToList();
if (nonMeasurableFields != null && nonMeasurableFields.Count > 0)
{
#region Outer For Loop
for (int index = 0; index < processedData.Count; index++)
{
var baseDict = processedData.ElementAt(index);
Dictionary<String, Object> compareDict = null;
#region Recursive Loop
for (int recursiveIndex = index + 1; recursiveIndex < processedData.Count; recursiveIndex++)
{
compareDict = processedData.ElementAt(recursiveIndex);
int matchesCount = 0;
#region comparison logic
foreach (var key in nonMeasurableFields)
{
var baseDictValue = baseDict[key];
var compareDictValue = compareDict[key];
if (baseDictValue == null && compareDictValue == null)
{
matchesCount++;
}
else
{
if (baseDictValue != null && compareDictValue == null)
{
matchesCount = 0;
}
else if (baseDictValue == null && compareDictValue != null)
{
matchesCount = 0;
}
else if (baseDictValue != null && compareDictValue != null)
{
if (baseDictValue.Equals(compareDictValue))
{
matchesCount++;
}
else
{
matchesCount = 0;
}
}
}
}
#endregion
#region If Match -- Combine
if (matchesCount == nonMeasurableFields.Count)
{
#region combine logic
// Combine the two dictionary ..
processedData.Remove(baseDict);
processedData.Remove(compareDict);
// combine the base and compare dict
Dictionary<String, Object> combinedDict = new Dictionary<string, object>();
var keyNeededInDict = baseDict.Keys.ToList();
foreach (var key in keyNeededInDict.ToList())
{
if (nonMeasurableFields.Contains(key))
{
combinedDict.Add(key, baseDict[key]);
}
else
{
Object value = Convert.ToDouble(baseDict[key]) + Convert.ToDouble(compareDict[key]);
combinedDict.Add(key, value);
}
}
processedData.Add(combinedDict);
index = -1; // Resetting the looping index so that the merging works for all values
recursiveIndex = -1; // Ensuring all the values are considered at least once whenever
// a change is made to the list (i.e merging the dict)
break;
#endregion
}
else
{
// No matches
// continue to next
}
#endregion
}
#endregion
}
#endregion
}
//获取可用于组合值的字段
var nonmeasurefields=report.datagrid\u字段。
其中(field=>field.dataType.Equals(ImFieldDatatype.STRING_值)| | field.dataType.Equals(ImFieldDatatype.DATE_值))。
选择(field=>field.name).ToList();
if(nonmeasurefields!=null&&nonmeasurefields.Count>0)
{
#外循环区域
for(int index=0;index //Get fields which could be used for combining values
var nonMeasurableFields = report.datagrid_fields.
Where(field => field.dataType.Equals(ImFieldDatatype.STRING_VALUE) || field.dataType.Equals(ImFieldDatatype.DATE_VALUE)).
Select(field => field.name).ToList();
if (nonMeasurableFields != null && nonMeasurableFields.Count > 0)
{
#region Outer For Loop
for (int index = 0; index < processedData.Count; index++)
{
var baseDict = processedData.ElementAt(index);
Dictionary<String, Object> compareDict = null;
#region Recursive Loop
for (int recursiveIndex = index + 1; recursiveIndex < processedData.Count; recursiveIndex++)
{
compareDict = processedData.ElementAt(recursiveIndex);
int matchesCount = 0;
#region comparison logic
foreach (var key in nonMeasurableFields)
{
var baseDictValue = baseDict[key];
var compareDictValue = compareDict[key];
if (baseDictValue == null && compareDictValue == null)
{
matchesCount++;
}
else
{
if (baseDictValue != null && compareDictValue == null)
{
matchesCount = 0;
}
else if (baseDictValue == null && compareDictValue != null)
{
matchesCount = 0;
}
else if (baseDictValue != null && compareDictValue != null)
{
if (baseDictValue.Equals(compareDictValue))
{
matchesCount++;
}
else
{
matchesCount = 0;
}
}
}
}
#endregion
#region If Match -- Combine
if (matchesCount == nonMeasurableFields.Count)
{
#region combine logic
// Combine the two dictionary ..
processedData.Remove(baseDict);
processedData.Remove(compareDict);
// combine the base and compare dict
Dictionary<String, Object> combinedDict = new Dictionary<string, object>();
var keyNeededInDict = baseDict.Keys.ToList();
foreach (var key in keyNeededInDict.ToList())
{
if (nonMeasurableFields.Contains(key))
{
combinedDict.Add(key, baseDict[key]);
}
else
{
Object value = Convert.ToDouble(baseDict[key]) + Convert.ToDouble(compareDict[key]);
combinedDict.Add(key, value);
}
}
processedData.Add(combinedDict);
index = -1; // Resetting the looping index so that the merging works for all values
recursiveIndex = -1; // Ensuring all the values are considered at least once whenever
// a change is made to the list (i.e merging the dict)
break;
#endregion
}
else
{
// No matches
// continue to next
}
#endregion
}
#endregion
}
#endregion
}
var lookup = dicList.ToLookup(x => new{
Product = x["Product"],
Region = x["Region"]});
var condensedDicList = lookup
.Select(x => new Dictionary<string, object>(){
{"Product",x.Key.Product},
{"Region",x.Key.Region},
{"Profit",x.Sum(d=>(int)d["Profit"])}
})
.ToList();
class MyData
{
public string Product{get;set;}
public string Region{get;set;}
public int Profit{get;set;}
}
IEnumerable<IDictionary<string, object>>
IEnumerable<IDictionary<string, object>> Merger(
IEnumerable<IDictionary<string, object>> source,
IEnumerable<string> keys,
IDictionary<string, Func<IEnumerable<object>, object>> aggregators)
{
var grouped = source.GroupBy(d => string.Join("|", keys.Select(k => d[k])));
foreach(var g in grouped)
{
var result = new Dictionary<string, object>();
var first = g.First();
foreach(var key in keys)
{
result.Add(key, first[key]);
}
foreach(var a in aggregators)
{
result.Add(a.Key, a.Value(g.Select(i => i[a.Key])));
}
yield return result;
}
}
var processedDictionaries = Merger(
rawListDict,
new[] { "Product", "Region" },
new Dictionary<string, Func<IEnumerable<object>, object>>
{
{ "Profit", objects => objects.Cast<int>().Sum() }
});
var aggregators = new Dictionary<string, Func<IEnumerable<object>, object>>();
aggregators.Add(
"Profit",
objects => objects.Cast<string>().Sum(s => double.Parse(s)));
var groupingKeys = new [] { "Product", "Region" };
var aggKey = "Profit";
List<Dictionary<String,Object>> rows = GetRows(); //provided
var results =
from r in rows
let groupingValues = groupingKeys.Select(key => r[key]).ToArray()
let groupingString = string.Join("|", groupingValues) //HACK - you better use an array comparer
let aggValue = Convert.ToInt32(r[aggKey])
group aggValue by groupingString into g
select new { Key = g.Key, Sum = g.Sum() }