使用LINQ提取特定类型的List元素
本文关键字:List 元素 类型 LINQ 提取 使用 | 更新日期: 2023-09-27 18:01:19
我有一个对象列表,我必须编写一个方法,该方法根据输入参数提取一些元素,该参数是Type数组。函数必须从列表中返回一个元素数组,每个元素都是类型数组中一个元素的实例。同时,这些元素必须从容器列表中删除,但前提是它们全部存在于列表中。通过Type.IsInstanceOfType(o)
方法实现类型比较。
class A {}
class B : A {}
class C : A {}
class D : A {}
public static A[] ExtractElements (List<A> list, Type[] specifiers) {...}
Type[] specifiers1 = new Type[2] {typeof(D), typeof(B)};
Type[] specifiers2 = new Type[3] {typeof(C), typeof(A), typeof(D)};
Type[] specifiers3 = new Type[2] {typeof(A), typeof(A)};
Type[] specifiers4 = new Type[2] {typeof(C), typeof(C)};
List<A> list = new List<A> {new B(), new A(), new D(), new C(), new A()};
A[] result1 = ExtractElements (list, specifiers1);
list = new List<A> {new B(), new A(), new D(), new C(), new A()};
A[] result2 = ExtractElements (list, specifiers2);
list = new List<A> {new B(), new A(), new D(), new C(), new A()};
A[] result3 = ExtractElements (list, specifiers3);
list = new List<A> {new B(), new A(), new D(), new C(), new A()};
A[] result4 = ExtractElements (list, specifiers4);
这个代码片段的结果将是:
result1 is {D, B}, list is {A, C, A}
result2 is {C, B, D}, list is {A, A}
result3 is {B, A}, list is {D, C, A}
result4 is empty array, list is {B, A, D, C, A}
作为一个单独的努力,是否可能编写一个类似的ExtractElements方法,仅当列表包含请求类型的项,其在列表中的顺序与类型输入数组中的元素顺序相对应时才返回非空数组,如以下
Type[] specifiers5 = new Type[2] {typeof(B), typeof(D)};
Type[] specifiers6 = new Type[2] {typeof(C), typeof(B)};
List<A> list = new List<A> {new B(), new A(), new D(), new C(), new A()};
A[] result5 = ExtractElements (list, specifiers5);
list = new List<A> {new B(), new A(), new D(), new C(), new A()};
A[] result6 = ExtractElements (list, specifiers6);
这个代码片段的结果将是:
result5 is {B, D}, list is {A, C, A}
result6 is empty array, list is {B, A, D, C, A}
我知道LINQ
是实现这一点的方式,但不幸的是我没有经验。
这听起来很适合Enumerable.OfType<T>()
。
如何:
public IEnumerable<TType> ExtractElements<TType>(IEnumerable<TType> list, IEnumerable<Type> specifiers) {
var specifiersList = specifiers.ToList();
return list.Where(t => specifiersList.Any(s => s.IsAssignableFrom(t.GetType())));
}
var specifiers5 = new[] {typeof(B), typeof(D)};
var list = new List<A> {new B(), new A(), new D(), new C(), new A()};
// you can call ToArray() if you want but ForEach won't be available on that
// and you'll need a standard foreach() loop
var result5 = ExtractElements(list, specifiers5).ToList();
result5.ForEach(Console.WriteLine);
有关Type.IsAssignableFrom()
的更多信息
这应该能得到你想要的一切。我在ExtractElements
方法中添加了一个可选参数,允许您启用/禁用订单匹配。
public static A[] ExtractElements (List<A> list, Type[] specifiers, bool orderMatters = false)
{
var allFound = true;
var listBackup = list.ToList(); // Make a backup copy
var returnList = new List<A>();
var earliestMatch = 0;
foreach (var spec in specifiers)
{
var item = list.FirstOrDefault (i => spec.IsAssignableFrom(i.GetType()));
if (item != null)
{
var matchPosition = list.IndexOf(item);
if (orderMatters && matchPosition < earliestMatch) // we have an out of order match
{
allFound = false;
break;
}
earliestMatch = matchPosition;
list.Remove(item);
returnList.Add(item);
}
else
{
allFound = false;
break;
}
}
if(!allFound)
{
// Can't just assign list to listBackup because we have to update the
// underlying values not the reference that was passed to the function.
list.Clear();
listBackup.ForEach(i => list.Add(i));
returnList.Clear();
}
return returnList.ToArray();
}
我建议抓取一个LinqPad的副本,以帮助您测试任何LINQ
语句并学习LINQ
的一般内容。