Linq查询从多个列表中选择单个字符串
本文关键字:选择 单个 字符串 string 查询 列表 Linq | 更新日期: 2023-09-27 18:04:53
我很难理解为什么我得到了这样的结果。
我有两个字符串列表:var list1 = new List<String> {"item 1", "item 2"};
var list2 = new List<String> { "item 3", "item 4" };
版本1 -输出:"item 2"
var item =
from x in (list1.Concat(list2))
where x.EndsWith("2")
select x;
Console.WriteLine(item.First());
版本2 -输出:"i"
var item =
from x in (list1.Concat(list2))
where x.EndsWith("2")
select x.First();
Console.WriteLine(item.First());
版本3 -输出:"System.Linq.Enumerable+WhereEnumerableIterator ' 1[System.String]"
var item =
from x in (list1.Concat(list2))
where x.EndsWith("2")
select x;
Console.WriteLine(item);
假设版本2输出"i",我希望版本3输出"item 2"。为什么会出现这种行为?
在版本3中,select x
返回符合条件的字符串的序列;它恰好是一个序列,其中只有一个元素。
Console.WriteLine
内部调用.ToString()
的任何你传递给它。因为IEnumerable<T>
没有有意义的字符串表示,所以. net中的默认是打印类型的字符串名称。
根据你的措辞,我认为你的部分困惑确实来自于对为什么版本2是这样工作的误解。在版本2中,select x.First()
实际上有点奇怪/巧合,因为字符串也是和IEnumerable<char>
,所以您可以对字符串执行LINQ操作。对于每个符合条件的结果,.First()
返回该char
序列的第一个元素。所以你说:
"对于每个符合我的条件的元素,选择第一个字符,然后返回匹配的所有第一个字符的序列。"
所以实际上,版本2中的item
是包含一个元素的IEnumerable<char>
。在IEnumerable<char>
上调用Console.WriteLine()
只会按顺序打印字符。所以你得到"i"
(注意:在我回答这个问题之后,我看到这个问题被编辑为在投影和结果中调用.First()
,所以关于将IEnumerable<char>
传递给Console.WriteLine
的位不再完全相关)
请记住,LINQ基本上是在处理集合,直到你显式地减少它们。例如,Select
只是一个投影或变换。它返回传递给它的经过转换的相同数量的项。Where
减少了集合,但它仍然是一个集合。
你的版本2是从字符串x.First()
选择第一个项目/字符,而你的第一个版本是从结果集->第一个字符串选择第一个项目。
版本1类似于- 从结果集中选择第一项
var item = (from x in (list1.Concat(list2))
where x.EndsWith("2")
select x).First(); //First complete string will be selected
和版本2类似于- 从结果集
中的字符串中选择第一项var item = from x in (list1.Concat(list2))
where x.EndsWith("2")
select x.First(); //only first char will be selected for string
第三种情况是选择一个IEnumerable<string>
,所以当你调用Console.WriteLine
时,它调用ToString
的默认实现,因此你得到
" System.Linq.Enumerable + WhereEnumerableIterator ' 1 system . string] ["
当使用First()
时,您正在具体化列表,导致迭代器执行。这是一种急切的执行。第三个版本使用select
,它没有实现列表;使用Defeered Execution
,它返回一个迭代器,因此调用ToString()
,返回迭代器名称
因为Where
返回一个IEnumerable
.
你写了相当于:
var whoKnows = list1.Concat(list2).Where(x => x.EndsWith("2"));
Console.WriteLine(whoKnows);
集合的ToString
只返回类名。
版本2中x
的类型为String
。版本1中item
的类型是IEnumerable
所以你的版本2返回一个字符列表,这些字符是每个字符串的第一个字符。在版本1中,item.First()
返回结果集的第一个元素,该元素是一个字符串。
//This raise a exception if no item found
var item=list1.Concat(list2).First(i => i.EndsWith("2"));
//this return default value (null) if no item found
var item2 = list1.Concat(list2).FirstOrDefault(i => i.EndsWith("2"));