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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/550556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 07:49:04  来源:igfitidea点击:

Using lambda expressions to get a subset where array elements are equal

c#lambda

提问by Erik Funkenbusch

I have an interesting problem, and I can't seem to figure out the lambda expression to make this work.

我有一个有趣的问题,我似乎无法弄清楚 lambda 表达式来完成这项工作。

I have the following code:

我有以下代码:

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 (???);
});

I want to return only those records in list in which element 0 of each string[] is equal to one of the element 0's in list2.

我只想返回列表中每个 string[] 的元素 0 等于 list2 中的元素 0 之一的那些记录。

list contains data like this:

列表包含这样的数据:

"000", "Data", "more data", "etc..."

list2 contains data like this:

list2 包含这样的数据:

"000", "different data", "even more different data"

Fundamentally, i could write this code like this:

从根本上说,我可以像这样编写这段代码:

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;

But, i'm trying to use generics and lambda's more, so i'm looking for a nice clean solution. This one is frustrating me though.. maybe a Find inside of a Find?

但是,我正在尝试使用泛型和 lambda 的更多,所以我正在寻找一个很好的干净的解决方案。不过,这让我很沮丧……也许是 Find 中的 Find?

EDIT: Marc's answer below lead me to experiment with a varation that looks like this:

编辑:Marc 在下面的回答让我尝试了一个看起来像这样的变化:

var z = list.Where(x => list2.Select(y => y[0]).Contains(x[0])).ToList();

I'm not sure how efficent this is, but it works and is sufficiently succinct. Anyone else have any suggestions?

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

采纳答案by Marc Gravell

You could join? I'd use two steps myself, though:

你能加入吗?不过,我自己会使用两个步骤:

var keys = new HashSet<string>(list2.Select(x => x[0]));
var data = list.Where(x => keys.Contains(x[0]));

If you only have .NET 2.0, then either install LINQBridgeand use the above (or similar with a Dictionary<>if LINQBridge doesn't include HashSet<>), or perhaps use nested Find:

如果您只有 .NET 2.0,那么要么安装LINQBridge并使用上面的(或类似的Dictionary<>if LINQBridge 不包括HashSet<>),或者可能使用嵌套Find

var data = list.FindAll(arr => list2.Find(arr2 => arr2[0] == arr[0]) != null);

note though that the Findapproach is O(n*m), where-as the HashSet<>approach is O(n+m)...

请注意,该Find方法是 O(n*m),而该HashSet<>方法是 O(n+m)...

回答by David Wengier

You could use the Intersect extension method in System.Linq, but you would need to provide an IEqualityComparer to do the work.

您可以在 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
    }

回答by DarcyThomas

Intersect may work for you. Intersect finds all the items that are in both lists.Ok re-read the question. Intersect doesn't take the order into account. I have written a slightly more complex linq expression that will return a list of items that are in the same position (index) with the same value.

相交可能对你有用。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"}

Explanation of the query:

查询说明:

Select a set of values and position of that value.

选择一组值和该值的位置。

Filter that set where the item in the same position in the second list has the same value.

设置第二个列表中相同位置的项目具有相同值的过滤器。

Select just the value (not the index as well).

只选择值(而不是索引)。

Note I used: list2.Skip(w.Index).FirstOrDefault() //instead of list2[w.Index]So that it will handle lists of different lengths.

注意我用过: list2.Skip(w.Index).FirstOrDefault() //instead of list2[w.Index]这样它就可以处理不同长度的列表。

If you know the lists will be the same length or list1 will always be shorter then list2[w.Index]would probably a bit faster.

如果您知道列表的长度相同或 list1 总是更短,那么list2[w.Index]可能会快一点。