简体   繁体   English

使用LINQ选择多个字段的简便方法

[英]Easy way to select more than one field using LINQ

Take a look of this sample object, 看一下这个样本对象,

public class Demo
{
    public string DisplayName { get; set; }

    public int Code1 { get; set; }

    public int Code2 { get; set; }

    ...
}

and lets say I want to put all codes ( Code1 , Code2 ) in one list ( IEnumerable )... one way is this one: 并且可以说,我希望把所有的代码( Code1Code2 )在一个列表( IEnumerable )......一个方法是这样:

var codes = demoList.Select(item => item.Code1).ToList();
codes.AddRange(demoList.Select(item => item.Code2));
//var uniqueCodes = codes.Distinct(); // optional

I know this is not a nice neither optimal solution, so I am curious to know what will be a better approach / (best practice)? 我知道这既不是最佳解决方案,也不是最佳解决方案,所以我很想知道哪种方法更好(/最佳实践)?

How about with SelectMany : 如何使用SelectMany

var codes = demoList.SelectMany(item => new[] { item.Code1, item.Code2 });

By the way, the idiomatic way of doing a concatenation in LINQ is with Concat : 顺便说一下,在LINQ中进行连接的惯用方式是使用Concat

var codes = demoList.Select(item => item.Code1)          
                    .Concat(demoList.Select(item => item.Code2));

Linq is not a silver bullet to kill everything Linq 不是杀死一切的灵丹妙药

For your intent i'd propose the following 为了您的意图,我建议以下内容

var codes = new List<int>(demoList.Count * 2);
foreach(var demo in demoList)
{
  codes.Add(demo.Code1);
  codes.Add(demo.Code2);
}

BENCHMARK 基准

I did a benchmark iterating a list of 1 million and 1 thousand instances with my solution and Ani's 我做了一个基准测试,用我的解决方案和Ani的解决方案迭代了100万和1000个实例

Amount: 1 million 金额:100万

Mine : 2ms 地雷:2ms

Ani's: 20ms Ani's:20ms

Amount 1000 items 数量1000件

Mine : 1ms 地雷:1ms

Ani's: 12ms Ani's:12ms

the sample code 示例代码

        List<MyClass> list = new List<MyClass>(1000);
        for (int i = 0; i < 100000; i++)
        {
            list.Add(new MyClass
            {
                Code1 = i,
                Code2 = i * 2,
            });
        }
        System.Diagnostics.Stopwatch timer1 = System.Diagnostics.Stopwatch.StartNew();
        var resultLinq = list.SelectMany(item => new[] { item.Code1, item.Code2 }).ToList();
        Console.WriteLine("Ani's: {0}", timer1.ElapsedMilliseconds);

        System.Diagnostics.Stopwatch timer2 = System.Diagnostics.Stopwatch.StartNew();
        var codes = new List<int>(list.Count * 2);
        foreach (var item in list)
        {
            codes.Add(item.Code1);
            codes.Add(item.Code2);
        }
        Console.WriteLine("Mine : {0}", timer2.ElapsedMilliseconds);
    }
// this won't return duplicates so no need to use Distinct.
var codes = demoList.Select(i=> i.Code1)
                    .Union(demoList.Select(i=>i.Code2));

Edited just for completeness (see @Ani answer) after some comments: 经过评论后,仅出于完整性考虑进行编辑(请参阅@Ani答案):

// Optionally use .Distinct()
var codes = demoList.Select(i=>i.Code1)
                    .Concat(demoList.Select(i=>i.Code2))
                    .Distinct();

即使您编写的代码是完美的,我也给您另一个选择

var output = Enumerable.Concat(demoList.Select(item => item.Code1).ToList(), demoList.Select(item => item.Code2).ToList()).ToList();

The Luis' answer is good enough for me. 路易斯的回答对我来说足够好了。 but I did re-factored it, using extension methods for any numbers of fields... and the optimal result still Luis's answer. 但是我确实对它进行了重构,对任何数量的字段都使用了扩展方法……而最佳结果仍然是路易斯的答案。 (example of 100000 records) (100000条记录的示例)

Ani's: 21
Luis: 4
Jaider's: 15

Here my extension method. 这是我的扩展方法。

public static IEnumerable<T> SelectExt<R, T>(this IEnumerable<R> list, params Func<R, T>[] GetValueList)
{
    var result = new List<T>(list.Count() * GetValueList.Length);
    foreach (var item in list)
    {
        foreach (var getValue in GetValueList)
        {
            var value = getValue(item);
            result.Add(value);
        }
    }

    return result;
}

The usage, will be: 用法为:

var codes = demoList.SelectExt(item => item.Code1, item => item.Code2).ToList();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM