根据定界符从现有列表中创建较小的列表

时间:2019-07-04 15:15:28

标签: c# list xamarin nested-lists

我有一个由较小列表的集合组成的列表。我需要根据特定值将聚合列表拆分为较小的列表。

我尝试使用.Take()方法,但是它使用一个整数,我不一定知道较小的列表将要持续多长时间。

我的列表大列表看起来像这样

List<T> Foo = new List<T>();
Foo.Add("Test1", "LineTypeA");
Foo.Add("Test2", "LineTypeA");
Foo.Add("Test3", "LineTypeB");
Foo.Add("Test4", "LineTypeA");
Foo.Add("Test5", "LineTypeB");

List<List<T> Bar = new List<ListT>>();
Bar.Add(Foo);

我需要能够根据“ LineTypeB”将“ Bar”拆分为较小的列表。因此,一个列表将包含3个元素,而另一个列表将包含以上示例中的两个元素。在该线程中有一个类似的解决方案可以执行我想做的事,但在python中-Python splitting a list based on a delimiter word

2 个答案:

答案 0 :(得分:0)

让我们假设您具有列表中将包含的类型:

public class MyItem
{
    public string Key { get; set; }

    public string Value { get; set; }

    public MyItem(string key, string value)
    {
        Key = key;
        Value = value;
    }
}

您已经创建了这样的初始列表:

List<MyItem> Foo1 = new List<MyItem>();
Foo1.Add(new MyItem("Test1", "LineTypeA"));
Foo1.Add(new MyItem("Test2", "LineTypeA"));
Foo1.Add(new MyItem("Test3", "LineTypeB"));
Foo1.Add(new MyItem("Test4", "LineTypeA"));
Foo1.Add(new MyItem("Test5", "LineTypeB"));

List<MyItem> Foo2 = new List<MyItem>();
Foo2.Add(new MyItem("Test1", "LineTypeA"));
Foo2.Add(new MyItem("Test2", "LineTypeA"));
Foo2.Add(new MyItem("Test3", "LineTypeB"));
Foo2.Add(new MyItem("Test4", "LineTypeA"));
Foo2.Add(new MyItem("Test5", "LineTypeB"));

List<MyItem> Foo3 = new List<MyItem>();
Foo3.Add(new MyItem("Test1", "LineTypeA"));
Foo3.Add(new MyItem("Test2", "LineTypeA"));
Foo3.Add(new MyItem("Test3", "LineTypeB"));
Foo3.Add(new MyItem("Test4", "LineTypeA"));
Foo3.Add(new MyItem("Test5", "LineTypeB"));


List<List<MyItem>> Bar = new List<List<MyItem>> ();
Bar.Add(Foo1);
Bar.Add(Foo2);
Bar.Add(Foo3);

接下来,您可以使用LINQ来制作一个平面列表(如果您只有一个内部列表(例如,只有Foo1),甚至可能不需要):

List<MyItem> flatList = Bar.SelectMany(innerList => innerList).ToList();
string expectedValue = "LineTypeB";

现在到最重要的部分,您可以通过为列表创建扩展方法来做到这一点:

public static class ListExtensionMethods
{
    public static List<List<MyItem>> SplitListByValue(this List<MyItem> list, string value)
    {
        List<List<MyItem>> splittedList = new List<List<MyItem>>() { new List<MyItem>() }; // initial set

        for (int i = 0; i < list.Count; i++)
        {
            var currentItem = list[i];
            if (i == 0 && currentItem.Value == value) //if the first element already meets the condition, add it to the first sublist and create new one
            {
                splittedList.LastOrDefault().Add(currentItem);
                splittedList.Add(new List<MyItem>());
            }
            else if (currentItem.Value == value)
            {
                splittedList.Add(new List<MyItem>()); //if i-th element meets the condition, create new sublist and add it there
                splittedList.LastOrDefault().Add(currentItem);
            }
            else
            {
                splittedList.LastOrDefault().Add(currentItem);
            }
        }

        return splittedList;
    }
}

然后您像在flatList上一样调用它:

var splitList = flatList.SplitListByValue(expectedValue);

我希望这会有所帮助。

答案 1 :(得分:0)

这是Python问题中答案的C#等效项。我将其更改为不使用定界符,而是使用确定项目是否为定界符的委托。另外,我还修复了当集合为空或第一项匹配时不返回空集合的问题。

public static IEnumerable<IEnumerable<T>> SplitOn<T>(
    this IEnumerable<T> items, 
    Func<T, bool> split)
{
    var g = new List<T>();
    foreach(var item in items)
    {
        if(split(item) && g.Count > 0)
        {
            yield return g;
            g = new List<T>();
        }

        g.Add(item);
    }

    if(g.Count > 0) yield return g;
}

然后,您可以将其用于这样的示例。

var results = Bar.SelectMany(x => x).SplitOn(x => x.Value == "LineTypeB");