找到匹配元素时从列表中减去值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了找到匹配元素时从列表中减去值相关的知识,希望对你有一定的参考价值。
public class ScenarioResults
{
public string ProductSubType { get; set; }
public string SubBook { get; set; }
public decimal? ScenarioValue { get; set; }
}
我有两个“ScenarioResults”对象列表。我需要获得一个新列表,其中的值与两个列表中的scenariovalue不同。
减法标准:
- 如果productsubtype,子书匹配两个列表中的对象,则减去两者中的scenariovalue。
- 如果在第一个列表中找不到匹配,则获取第一个列表对象
- 如果在第二个列表中找不到匹配,则获取-second list对象
StartResults和EndResults是我拥有的两个列表。我将结果添加到结果列表中我编写了以下代码并且它有效:
var results = new List<ScenarioResults>();
foreach (var endResult in resultsEnd)
{
var result = ScenarioResults.Clone(endResult);
var startResult = resultsStart.FirstOrDefault(x.SubBook == result.SubBook && x.ProductSubType == result.ProductSubType);
if (startResult == null)
{
result.ScenarioValue = endResult.ScenarioValue;
results.Add(result);
}
else
{
result.ScenarioValue = endResult.ScenarioValue - startResult.ScenarioValue;
results.Add(result);
}
}
foreach (var startResult in resultsStart)
{
var result = ScenarioResults.Clone(startResult);
var endResult = resultsEnd.Any(x.SubBook == result.SubBook && x.ProductSubType == result.ProductSubType);
if (!endResult)
{
result.ScenarioValue = -startResult.ScenarioValue;
results.Add(result);
}
}
有没有更好的方法来解决这个问题?如何提高这个性能?
答案
如果您使用在搜索中使用的组合键对两个集合进行分组,即{SubBook, ProductSubType}
,则可以简化和加快代码
var startDict = resultsStart
.GroupBy(r => new {r.SubBook, r.ProductSubType})
.ToDictionary(g => g.Key, g => g.First());
var endDict = resultsEnd
.GroupBy(r => new {r.SubBook, r.ProductSubType})
.ToDictionary(g => g.Key, g => g.First());
foreach (var key in startDict.Keys.Union(endDict.Keys)) {
var hasStart = startDict.TryGetValue(key, out var start);
var hasEnd = endDict.TryGetValue(key, out var end);
if (hasStart && hasEnd) {
... // Construct the difference with subtraction
} else if (hasStart) {
... // Construct the difference where only the start is present
} else if (hasEnd) {
... // Construct the difference where only the end is present
}
}
由于哈希查找,该解决方案是O(S + E),而原始解决方案是O(S * E),因为嵌套线性搜索。
另一答案
用纯LINQ :)。这只是一个展示可能必须稍微调整但仍然可以做到这一点。只是为了表明一个想法。
List<ScenarioResults> a = new List<ScenarioResults> { new ScenarioResults { ProductSubType = "1", SubBook = "1", ScenarioValue = 10}, new ScenarioResults { ProductSubType = "2", SubBook = "2", ScenarioValue = 10 } };
List<ScenarioResults> b = new List<ScenarioResults> { new ScenarioResults { ProductSubType = "2", SubBook = "2", ScenarioValue = 10 }, new ScenarioResults { ProductSubType = "3", SubBook = "3", ScenarioValue = 10 } };
List<ScenarioResults> result = a.Concat(b.Select(_ => new ScenarioResults { ProductSubType = _.ProductSubType, SubBook = _.SubBook, ScenarioValue = -_.ScenarioValue ?? 0}))
.GroupBy(x => new {x.ProductSubType, x.SubBook})
.SelectMany(g => g.Select(_ => new ScenarioResults { ProductSubType = _.ProductSubType, SubBook = _.SubBook, ScenarioValue = (g.First().ScenarioValue ?? 0) + g.Skip(1).Sum(v => v.ScenarioValue)}))
.Distinct(new EqualityComparer())
.ToList();
其中EqualityComparer
是这样的:
public class EqualityComparer : IEqualityComparer<ScenarioResults>
{
public bool Equals(ScenarioResults x, ScenarioResults y)
{
return x.ProductSubType == y.ProductSubType && x.SubBook == y.SubBook;
}
public int GetHashCode(ScenarioResults obj)
{
return obj.ProductSubType.GetHashCode() ^ obj.SubBook.GetHashCode();
}
}
以上是关于找到匹配元素时从列表中减去值的主要内容,如果未能解决你的问题,请参考以下文章