LINQ列表搜索多个列表。返回单个列表

时间:2017-03-21 20:07:44

标签: c# linq list recursion

我希望构建一个函数来创建一个或多个列表。

此元素列表根据动态列表列表中的值确定独奏。

例如 列表A保存一个包含列表B的对象,列表B包含一个包含列表C的对象

在列表A B或C中,他们有可能持有特殊值。

我需要创建一个搜索每个列表的函数,只返回保存特殊值的值。

我试着研究递归函数,我认为我很接近。

public ObservableCollection<ListViewItem> RecursiveActionBuilder(List<IMetaData> pList)
    {
        if (pList == null)
            return null;

        List<ActionObject> actions = new List<ActionObject>();

        for (int x = 0; x < pList.Count; x++)
        {
            ActionObject child = RecursiveActionBuilder(pList[x]);
            if (child == null)
                continue;
            else
                actions.Add(child);
        }

        ObservableCollection<ListViewItem> items = new ObservableCollection<Models.Items.ListViewItem>();

        for (int x = 0; x < actions.Count; x++)
            items.Add(new ListViewItem()
            {
                Values = new ListViewValue[]
                {
                    new ListViewValue() { Value = actions[x].Command },
                    new ListViewValue() { Value = actions[x].Target },
                    new ListViewValue() { Value = actions[x].Value },
                    new ListViewValue() { Value = actions[x].Comment }
                }
            });

        return items;
    }

    public ActionObject RecursiveActionBuilder(IMetaData pObj)
    {
        if (pObj == null)
            return null;

        if (pObj.Children == null)
        {
            if (pObj.Tag == Enums.TestType.Action)
                return pObj as ActionObject;
            else
                return null;
        }


        ActionObject action = new ActionObject();

        for (int x = 0; x < pObj.Children.Count; x++)
        {
            ActionObject child = RecursiveActionBuilder(pObj.Children[x]);
            if (child == null)
                continue;
            else return child;
        }
        return null;
    }

然而,它并没有抓住所有的行动&#39;它只抓一个,然后跳出来。

思想?

1 个答案:

答案 0 :(得分:2)

问题显然是因为这种方法

public ActionObject RecursiveActionBuilder(IMetaData pObj)

返回单个对象,而不是问题所暗示的多个对象。

可以修复,但我会建议你采用略有不同的方法。

遵循DRY原则,在这种情况下你真正需要的是类似LINQ的方法,它会像你的IMetaData那样展平树结构(根据你的代码包含List<IMetaData> Children属性/字段)。例如,您可以使用我对How to flatten tree via LINQ?

的回答中的自定义扩展方法
public static class TreeHelpers
{
    public static IEnumerable<T> Expand<T>(
        this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
    {
        var stack = new Stack<IEnumerator<T>>();
        var e = source.GetEnumerator();
        try
        {
            while (true)
            {
                while (e.MoveNext())
                {
                    var item = e.Current;
                    yield return item;
                    var elements = elementSelector(item);
                    if (elements == null) continue;
                    stack.Push(e);
                    e = elements.GetEnumerator();
                }
                if (stack.Count == 0) break;
                e.Dispose();
                e = stack.Pop();
            }
        }
        finally
        {
            e.Dispose();
            while (stack.Count != 0) stack.Pop().Dispose();
        }
    }
}

现在,您可以利用LINQ的全部功能来解决您的具体问题:

public ObservableCollection<ListViewItem> RecursiveActionBuilder(List<IMetaData> pList)
{
    if (pList == null)
        return null;

    var items = pList
        .Expand(e => e.Children)
        .Select(e => e.Children == null && e.Tag == Enums.TestType.Action ? e as ActionObject : null)
        .Where(e => e != null)
        .Select(e => new ListViewItem()
        {
            Values = new ListViewValue[]
            {
                new ListViewValue() { Value = e.Command },
                new ListViewValue() { Value = e.Target },
                new ListViewValue() { Value = e.Value },
                new ListViewValue() { Value = e.Comment }
            }
        });

    return new ObservableCollection<ListViewItem>(items);
}