C# 使用LINQ从上一次迭代中获取参数

C# 使用LINQ从上一次迭代中获取参数,c#,linq,linq-to-objects,C#,Linq,Linq To Objects,如何使用LINQ在没有迭代的情况下执行此操作 string[] flatSource = {"region1", "subregion1", "region2", "sub1", "sub2", "region3", "sub1", "sub2"}; string previousRegion = ""; foreach (var item in flatSource) { if

如何使用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};
 }

也许你会发现这个方法很有用。

也许你会发现这个方法很有用。

你目前的解决方案很好;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
条件由final
Where
子句处理;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
条件由final
Where
子句处理。

似乎我没有足够仔细地阅读这个问题。因此,下面的扩展可能有用,但对这个问题没有帮助

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.");
    }
}
公共静态类IEnumerableOfExtensions
{
之前的公共静态T(此IEnumerable源,Func条件)
{
if(source==null)
抛出新的ArgumentNullException(“源”);
如果(条件==null)
抛出新的ArgumentNullException(“条件”);
使用(var e=source.GetEnumerator())
{
var first=真;
之前的var=默认值(T);
while(如MoveNext())
{
如果(条件(当前)
{
如果(第一)
抛出新ArgumentOutOfRangeException(“条件”,“第一个元素对应于条件”);
提前返回;
}
第一个=假;
前=e.电流;
}
}
抛出新ArgumentOutOfRangeException(“条件”,“没有与条件对应的元素”);
}
}

我似乎没有仔细阅读这个问题。因此,下面的扩展可能有用,但对这个问题没有帮助

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.");
    }
}
公共静态类IEnumerableOfExtensions
{
之前的公共静态T(此IEnumerable源,Func条件)
{
if(source==null)
抛出新的ArgumentNullException(“源”);
如果(条件==null)
抛出新的ArgumentNullException(“条件”);
使用(var e=source.GetEnumerator())
{
var first=真;
之前的var=默认值(T);
while(如MoveNext())
{
如果(条件(当前)
{
如果(第一)
抛出新ArgumentOutOfRangeException(“条件”,“第一个元素对应于条件”);
提前返回;
}
第一个=假;
前=e.电流;
}
}
抛出新ArgumentOutOfRangeException(“条件”,“没有与条件对应的元素”);
}
}

您可以在Net 4.0中使用Zip在一条语句中完成:

return
 flatSource.Where(i=>SomeRegionDictionary.Contains(i)).Zip(arr.Skip(1),
  (first, second) => new SubregionWithRegion{Region = first, SubRegion = second});

如果您没有Net 4.0,您可以使用以下实现:

您可以使用Net 4.0中的Zip在一条语句中实现:

return
 flatSource.Where(i=>SomeRegionDictionary.Contains(i)).Zip(arr.Skip(1),
  (first, second) => new SubregionWithRegion{Region = first, SubRegion = second});

如果您没有Net 4.0,您可以使用以下实现:

最终查询如何接近解决OP的原始问题?@Ani:您是对的。我只是没有仔细阅读这个问题。所以我在这里给出了我的答案,但你的答案似乎解决了具体问题。最终的查询如何接近于解决OP的原始问题?@Ani:你说得对。我只是没有仔细阅读这个问题。所以我在这里给出了我的答案,但你的答案似乎解决了具体问题。