[英]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: 并且可以说,我希望把所有的代码(
Code1
, Code2
)在一个列表( 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.