使用lambda表达式获取数组元素相等的子集

时间:2009-02-15 09:04:16

标签: c# lambda

我有一个有趣的问题,我似乎无法找出lambda表达式来使这个工作。

我有以下代码:

List<string[]> list = GetSomeData(); // Returns large number of string[]'s
List<string[]> list2 = GetSomeData2(); // similar data, but smaller subset
&nbsp;
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();

我不确定这是多么高效,但它有效并且足够简洁。其他人有什么建议吗?

3 个答案:

答案 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]可能会更快一些。