根据一定的标准将列表拆分为两个列表
本文关键字:列表 两个 拆分 标准 | 更新日期: 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