如何在没有迭代的情况下使用LINQ执行此操作?
string[] flatSource = {"region1", "subregion1",
"region2", "sub1", "sub2",
"region3", "sub1", "sub2"};
string previousRegion = "";
foreach (var item in flatSource)
{
if (SomeRegionDictionary.Contains(item))
previousRegion = item; //This is what I can't figure out
else
yield return new SubregionWithRegion{Region = previousRegion, SubRegion = item};
}
答案 0 :(得分:3)
您当前的解决方案很好; LINQ不是这种有状态查询的理想选择。 这是一个纯LINQ解决方案;它并不理想,因为它有点神秘和具有二次复杂性,但功能相同:
return flatSource.Select((item, index) =>
new SubregionWithRegion
{
Region = flatSource.Take(index + 1)
.LastOrDefault(SomeRegionDictionary.ContainsKey) ?? "",
SubRegion = item
})
.Where(srwr => !SomeRegionDictionary.ContainsKey(srwr.SubRegion));
循环的有状态性质由Take
+ LastOrDefault
个查询处理,棘手的else
条件由最终的Where
子句处理。
答案 1 :(得分:2)
似乎我没有仔细阅读这个问题。所以下面的扩展可能有用,但不是这个问题。
public static class IEnumerableOfTExtensions
{
public static T Before<T>(this IEnumerable<T> source, Func<T, bool> condition)
{
if (source == null)
throw new ArgumentNullException("source");
if (condition == null)
throw new ArgumentNullException("condition");
using (var e = source.GetEnumerator())
{
var first = true;
var before = default(T);
while (e.MoveNext())
{
if (condition(e.Current))
{
if (first)
throw new ArgumentOutOfRangeException("condition", "The first element corresponds to the condition.");
return before;
}
first = false;
before = e.Current;
}
}
throw new ArgumentOutOfRangeException("condition", "No element corresponds to the condition.");
}
}
答案 2 :(得分:1)
也许你会发现Enumerable.Aggregate方法很有用。
答案 3 :(得分:1)
你可以在一个声明中使用Zip in Net 4.0:
return
flatSource.Where(i=>SomeRegionDictionary.Contains(i)).Zip(arr.Skip(1),
(first, second) => new SubregionWithRegion{Region = first, SubRegion = second});
如果您没有Net 4.0,则可以使用此实现:Zip Me Up