【发布时间】:2018-04-28 12:04:48
【问题描述】:
我有一个对象集合IEnumerable<object> obs。
我还有另一个对象集合IEnumerable<object> data。
对于obs 中的每个ob,我需要在data 中找到与ob 在某个属性中具有相同值的第一项。例如,我可能正在寻找data 中与ob 具有相同ToString() 值的第一项。当找到属性值匹配的第一项时,我对找到的数据项执行一些操作,然后检查obs 中的下一个ob。如果没有找到,我会抛出一个错误。
这是一个幼稚的方法:
foreach (object ob in obs)
{
foreach (object dataOb in data)
if (ob.ToString() == dataOb.ToString())
{
... // do something with dataOb
goto ContinueOuter;
}
throw new Exception("No matching data found.");
ContinueOuter: ;
}
缺点是我每次都计算dataOb.ToString(),没必要。
我可以缓存它:
IDictionary<object, string> dataToDataStr = new Dictionary<object, string>();
foreach (object dataObj in data) // collect all ToString values in advance
dataToDataStr.Add(dataObj, dataObj.ToString());
foreach (object ob in obs)
{
foreach (object dataOb in dataToDataStr.Keys)
if (ob.ToString() == dataToDataStr[dataOb])
{
... // do something with dataOb
goto ContinueOuter;
}
throw new Exception("No matching data found.");
ContinueOuter: ;
}
缺点是我计算了所有ToString() 值,即使它可能不是必需的。我可能会在数据收集的前半部分找到所有匹配的数据对象。
我怎样才能懒惰地构建dataToDataStr 字典(或任何其他可让我检索对象及其唯一一次计算的 ToString 值的可枚举数据结构)?
这是我想到的代码(与伪代码混合):
IDictionary<object, string> dataToDataStr = new Dictionary<object, string>();
object lastProcessedDataOb = null;
foreach (object ob in obs)
{
foreach (object dataOb in dataToDataStr.Keys)
if (ob.ToString() == dataToDataStr[dataOb])
{
... // do something with dataOb
goto ContinueOuter;
}
foreach (object dataOb in data STARTING AFTER lastProcessedDataOb)
// if lastProcessedDataOb == null, start with the first entry of data
{
dataToDataStr.Add(dataOb, dataOb.ToString();
lastProcessedDataOb = dataOb;
if (ob.ToString() == dataToDataStr[dataOb])
{
... // do something with dataOb
goto ContinueOuter;
}
}
throw new Exception("No matching data found.");
ContinueOuter: ;
}
我知道如果 data 是 LinkedList 或任何具有索引访问的集合(然后我可以将链表节点或索引存储为 lastProcessedDataOb),这很容易,但事实并非如此 - 它是IEnumerable。也许这里可以使用yield return?
【问题讨论】:
-
也许你应该首先描述为什么你通过 ToString 比较你的对象。那感觉不对。为什么不使用实现 Equals/GetHashcode 的标准方法或正确实现 IEquatable/IComparable 接口?如果计算成本很高,则该实现可能包含缓存机制。这将使此类课程的用户的生活更轻松。
-
您的评论与问题的重点无关(懒惰地建立可枚举)。另外,我确实写了“我需要在数据中找到与 ob 的某个属性具有相同值的第一项。例如 [...]
ToString[...]”。
标签: c# lazy-evaluation enumerable