我有一个有趣的问题,我似乎无法找出lambda表达式来使这个工作。
我有以下代码:
List<string[]> list = GetSomeData(); // Returns large number of string[]'s
List<string[]> list2 = GetSomeData2(); // similar data, but smaller subset
List<string[]> newList = list.FindAll(predicate(string[] line){
return (???);
});
我想只返回列表中的那些记录,其中每个字符串[]的元素0等于list2中的元素0之一。
列表包含如下数据:
"000", "Data", "more data", "etc..."
list2包含这样的数据:
"000", "different data", "even more different data"
从根本上说,我可以这样编写这样的代码:
List<string[]> newList = new List<string[]>();
foreach(var e in list)
{
foreach(var e2 in list2)
{
if (e[0] == e2[0])
newList.Add(e);
}
}
return newList;
但是,我正在尝试使用泛型和lambda,所以我正在寻找一个很好的清洁解决方案。这个让我感到沮丧..也许是在Find中查找?
编辑: Marc在下面的回答让我尝试了一个看起来像这样的变体:
var z = list.Where(x => list2.Select(y => y[0]).Contains(x[0])).ToList();
我不确定这是多么高效,但它有效并且足够简洁。其他人有什么建议吗?
答案 0 :(得分:11)
var keys = new HashSet<string>(list2.Select(x => x[0]));
var data = list.Where(x => keys.Contains(x[0]));
如果你只有.NET 2.0,那么安装LINQBridge并使用上面的内容(如果LINQBridge不包含Dictionary<>
,则使用HashSet<>
),或者使用嵌套Find
:
var data = list.FindAll(arr => list2.Find(arr2 => arr2[0] == arr[0]) != null);
注意虽然Find
方法是O(n * m),其中 - HashSet<>
方法是O(n + m)......
答案 1 :(得分:3)
您可以在System.Linq中使用Intersect扩展方法,但是您需要提供IEqualityComparer来完成工作。
static void Main(string[] args)
{
List<string[]> data1 = new List<string[]>();
List<string[]> data2 = new List<string[]>();
var result = data1.Intersect(data2, new Comparer());
}
class Comparer : IEqualityComparer<string[]>
{
#region IEqualityComparer<string[]> Members
bool IEqualityComparer<string[]>.Equals(string[] x, string[] y)
{
return x[0] == y[0];
}
int IEqualityComparer<string[]>.GetHashCode(string[] obj)
{
return obj.GetHashCode();
}
#endregion
}
答案 2 :(得分:0)
Intersect可能适合您。
Intersect查找两个列表中的所有项目。
好的,重新阅读这个问题。 Intersect不会考虑订单。
我写了一个稍微复杂的linq表达式,它将返回一个具有相同值的相同位置(索引)的项目列表。
List<String> list1 = new List<String>() {"000","33", "22", "11", "111"};
List<String> list2 = new List<String>() {"000", "22", "33", "11"};
List<String> subList = list1.Select ((value, index) => new { Value = value, Index = index})
.Where(w => list2.Skip(w.Index).FirstOrDefault() == w.Value )
.Select (s => s.Value).ToList();
Result: {"000", "11"}
查询说明:
选择一组值和该值的位置。
过滤设置第二个列表中相同位置的项具有相同值的位置。
仅选择值(不是索引)。
注意我使用过:
list2.Skip(w.Index).FirstOrDefault()
//instead of
list2[w.Index]
这样它就可以处理不同长度的列表。
如果您知道列表长度相同或者list1总是更短,那么list2[w.Index]
可能会更快一些。