根据特定条件将列表拆分为两个列表

时间:2014-06-11 20:47:02

标签: c# list

另一个程序正在向我的程序传递一个对象列表。这些对象有一个名为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"
    }
}

4 个答案:

答案 0 :(得分:6)

这将是我接近它的方式(认为它使用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();
}

答案 1 :(得分:1)

尝试此算法。

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

答案 2 :(得分:1)

另一种选择是使用聚合。以下内容将原始集拆分为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();

答案 3 :(得分:1)

另一个替代解决方案(对于给定的示例输入)将使用Enumerable.Skip跳过第一个元素,然后使用Enumerable.SkipWhile方法获取第一个列表和List.Remove方法在拆分字后检索第二个列表(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