根据一定的标准将列表拆分为两个列表

本文关键字:列表 两个 拆分 标准 | 更新日期: 2023-09-27 18:08:17

另一个程序正在向我的程序传递一个对象列表。这些对象有一个名为Title的属性,在这个列表中,其中一个对象的标题将与第一个对象的标题匹配。我想把这个列表分成两个列表,使用第二个与第一个具有相同标题的对象作为标志,将剩余的对象写入另一个列表。我已经写了一个小的例子程序,表明我试图完成。我希望有人能给我指出正确的方向。

static void Main(string[] args)
{
    var names = new string[] {"Frank", "Jules", "Mark", "Allan", "Frank", "Greg", "Tim"};
    var listA = new List<string>();
    var listB = new List<string>();
    foreach (var name in names)
    {
        // Add all names to listA, until name is the next "Frank".  
        // If name is the next "Frank" add name and all remaining
        // names to listB.
        // So, listA would contain "Frank", "Jules", "Mark", "Allan"
        // listB would contain "Frank", "Greg", "Tim"
    }
}

根据一定的标准将列表拆分为两个列表

我将如何处理它(虽然它使用了LINQ,但你可以不使用):

void Main()
{
        var names = new string[] {"Frank", "Jules", "Mark", "Allan", "Frank", "Greg", "Tim"};
        var listA = new List<string>();
        var listB = new List<string>();
        // I'm not entirely sure where this comes from other than it's always
        // the first element in the "names" list.
        var needle = names[0]; // "Frank"
        // this finds the location of the second "Frank"
        var splitLocation = Array.IndexOf(names, needle, 1);
        // here we grab the first elements (up to the splitLocation)
        listA = names.Take(splitLocation).ToList();
        // here we grab everything past the splitLocation
        // (starting with the second "Frank")
        listB = names.Skip(splitLocation).ToList();
}

试试这个算法

Create a boolean flag with a value of false.
Iterate through the names:
    If the current name matches the first name:
        Set the flag to true
    If the flag is true:
        Add the current name to the second list
    Else:
        Add the current name to the first list

另一个选择是使用聚合。下面将原始集合拆分为n个集合。

var names = new[] { "Frank", "Jules", "Mark", "Allan", "Frank", "Greg", "Tim", "Frank", "Anna" };
string separator = names.First();
var aggregated = names.Aggregate(new List<List<string>>(), (arr, s) =>
{
    if (s == separator)
        arr.Add(new List<string> { s });
    else
        arr.Last().Add(s);
    return arr;
});

如果你想要严格的1或2个集合,那么下面的代码可以工作:

var names = new[] { "Frank", "Jules", "Mark", "Allan", "Frank", "Greg", "Tim", "Frank", "Anna" };
string separator = names.First();
var aggregated = names.Aggregate(new List<List<string>>(), (arr, s) =>
{
    if (s == separator && arr.Count < 2)
        arr.Add(new List<string> { s });
    else
        arr.Last().Add(s);
    return arr;
});
var listA = aggregated[0];
var listB = aggregated.Skip(1).FirstOrDefault();

另一个替代解决方案(对于给定的示例输入)是使用Enumerable。跳过跳过第一个元素,然后使用Enumerable。SkipWhile方法获取第一个列表和第二个列表。删除在分割词之后检索第二个列表的方法(TODO:添加异常处理,例如,如果列表为空):

public static class ProjectExtensions
{
    public static List<String> SplitTo(this List<String> source, String word)
    {
        // take first occurrence
        var result = new List<String> { source.First() };
        // skip already added (first item) and take all until search phrase
        result.AddRange(source.Skip(1).TakeWhile (s => s != word));
        return result;
    }
    public static List<String> SkipTo(this List<String> source, String word)
    {
        var result = source;
        // skip all until search phrase and take the rest
        result.RemoveRange(0, source.SplitTo(word).Count);
        return result;
    }
}

用法如下:

var names = new List<String> {"Frank", "Jules", "Mark", "Allan", "Frank", "Greg", "Tim"};
var listA = names.SplitTo("Frank");
var listB = names.SkipTo("Frank");
foreach (var a in listA)
{
    Console.WriteLine(a);
}
Console.WriteLine("---------");
foreach (var b in listB)
{
    Console.WriteLine(b);
}

输出为:

Frank
Jules
Mark
Allan
---------
Frank
Greg
Tim