简体   繁体   English

请解释这个 C# LINQ 语句

[英]Please Explain this C# LINQ statement

I found this piece of code on stackoverflow some time ago, but can't seem to find it again.前段时间在stackoverflow上找到了这段代码,但是好像又找不到了。 All credit to the author.全部归功于作者。 Sorry I could not link.对不起,我无法链接。

QUESTION?题? Can some C# LINQ guru please break down this statement step by step as I am having difficulty understanding it.某些 C# LINQ 大师能否请逐步分解此语句,因为我很难理解它。 It certainly works well and does the job, but how?它当然运行良好并且可以完成工作,但是如何呢?

Line to Split分割线

var line = $"13351.750815 26646.150876 6208.767863 26646.150876 1219.200000 914.400000 0.000000 1 \"Beam 1\" 0 1 1 1 0 1 1e8f59dd-142d-4a4d-81ff-f60f93f674b3";
var splitLineResult = line.Trim().Split('"')
                                    .Select((element, index) => index % 2 == 0
                                    ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                                    : new string[] { element })
                                    .SelectMany(element => element).ToList();

Result of Statement in LinqPad LinqPad 中的语句结果
图片

You need to begin by analysing the input you have in hand.您需要从分析手头的输入开始。

13351.750815 26646.150876 6208.767863 26646.150876 1219.200000 914.400000 0.000000 1 "Beam 1" 0 1 1 1 0 1 1e8f59dd-142d-4a4d-81ff-f60f93f674b3

The input consists of few alphanumeric strings separated by Whitespace .输入由几个由Whitespace分隔的字母数字字符串组成。 However, there is one special case that needs to be handled as well.但是,还有一种特殊情况需要处理。 The word " Beam 1 " is enclosed in Quotes . Beam 1 ”一词包含在Quotes 中

Now, let's break down the Linq statement.现在,让我们分解 Linq 语句。

 line.Trim().Split('"')

The first statement splits the input based on the delimiter Quotes .第一个语句根据分隔符Quotes拆分输入。 This splits the string into 3 parts.这将字符串分成 3 部分。

在此处输入图片说明

As you can observe the first( in 0th Index ) and Last( in index position 2 ) needs to be split further while, the element in the in index position 1 has already been parsed.正如您可以观察到的第一个(在第 0 个索引中)和最后一个(在索引位置 2 中)需要进一步拆分,而索引位置 1 中的元素已经被解析。 This is where the second part of Linq statement comes into picture.这就是 Linq 语句的第二部分出现的地方。

.Select((element, index) => index % 2 == 0
                                    ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                                    : new string[] { element })

In the above statement the Select((element, index) => index % 2 == 0 part checks if the current index position is in an even position. If so, it needs to be split the substring further based on delimiter ' ' (whitespace) . Otherwise, it creates an array with single entity 'Beam 1'在上面的语句中Select((element, index) => index % 2 == 0部分检查当前索引位置是否在偶数位置。如果是,则需要根据分隔符' ' (whitespace)否则,它会创建一个包含单个实体“Beam 1”的数组

At the end of the second part, what you get is a collection 3 sub-collections of alphanumeric strings ( IEnumerble<string[]> ).在第二部分的结尾,您得到的是一个集合 3 个字母数字字符串的IEnumerble<string[]>IEnumerble<string[]> )。

在此处输入图片说明

What now needs to be done is create a collection by flattening the parent collection.现在需要做的是通过展平父集合来创建一个集合。 This done using Enumerable.SelectMany .这是使用Enumerable.SelectMany完成的。

.SelectMany(element => element).ToList();

在此处输入图片说明

Hope that helped in understanding the Linq query better希望有助于更好地理解 Linq 查询

Breaking up the statement打破声明


    var splitLineResult = line.Trim().Split('"')
                            .Select((element, index) => index % 2 == 0
                            ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                            : new string[] { element }).ToList()
                            .SelectMany(element => element).ToList();
                                    

  1. Trim() : Removes any spaces in the beginning or the end. Trim()删除开头或结尾的 任何空格

  2. Split('"') :Split the string into an array of string with double quote as a delimiter Split('"') :将字符串拆分为以双引号为分隔符的字符串数组

  3. Select() : Only select a specific part from the element being iterated. Select()仅从正在迭代的元素中选择特定部分 In this scenario, its the element and its index in the entire string (starts with 0).在这种情况下,它是整个字符串中的元素及其索引(从 0 开始)。

  4. Within your select statement, you have %2 ==0 .. which is true only for every other element.在您的 select 语句中,您有%2 ==0 .. 这仅适用于所有其他元素。 (skips 1) (跳过 1)

  5. You can do an if else statement with ?你可以? and ::

    a.一种。 If true print 1 else print 0 can be thought of as true ? print 1 : print 0 If true print 1 else print 0可以被认为是true ? print 1 : print 0 true ? print 1 : print 0

  6. SelectMany() : Selects all the elements that are returned. SelectMany()选择所有返回的元素 Instead of returning 3 arrays, it returns the elements from each of the array.它不是返回 3 个数组,而是返回每个数组中的元素。

  7. ToList() : Converts the array to a list. ToList()将数组转换为列表。

Seems like there are some really good answers here already, but I had already almost finished mine when I saw people had beat me to it, so here's my version.似乎这里已经有一些非常好的答案,但是当我看到人们击败我时,我几乎已经完成了我的答案,所以这是我的版本。 Hope it brings something to the table.希望它能带来一些东西。
My approach was writing it out in non Linq code with comments我的方法是用带有注释的非 Linq 代码写出来

var line = $"13351.750815 26646.150876 6208.767863 26646.150876 1219.200000 914.400000 0.000000 1 \"Beam 1\" 0 1 1 1 0 1 1e8f59dd-142d-4a4d-81ff-f60f93f674b3";
line = line.Trim(); //remove leading and trailing white space
var tempArray1 = line.Split('"'); //split the line to a string array on "
                                  //so the string array we get, is everything before, between, and after "

//.Select((element, index)
//Basically doing a for-loop on the array we got
List<string[]> tempListForElements = new List<string[]>(); //initialize a temporary list of string arrays we're going to be using
for (var index = 0; index < tempArray1.Length; index++)
{
    var element = tempArray1[index];

    //now we're getting to the ternary, which is basically like an inline if-else statement
    //index % 2 == 0 ? <if true> : <if false>
    //if remainder of division by 2 is 0, so basically a way of doing two 
    //different things for every other iterator of the loop
    if (index % 2 == 0)
    {
        //if on the first or last iteraton on the loop (before and after " in the line)
        tempListForElements.Add(element.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries));  //we create yet another string array splitting on each whitespace and add it to our temporary list
    }
    else
    {
        //if on the second iteraton on the loop (between ")
        tempListForElements.Add(new string[] { element }); //we're creating yet another string array, this time there's just one element in the array though, and then add it to our temporary list
    }
}

//.SelectMany(element => element).ToList()
//we're basically turning out list of 3 string array into one string array
//can't be asked to type it out in non linq since just realized there are some good answers here already,
//but imagine initializing a string array with the correct size and then a foreach loop adding each string to it in order.

if you convert this Linq in normal for loop it will look like this.如果您在普通 for 循环中转换此 Linq,它将如下所示。

var line = $"13351.750815 26646.150876 6208.767863 26646.150876 1219.200000 914.400000 0.000000 1 \"Beam 1\" 0 1 1 1 0 1 1e8f59dd-142d-4a4d-81ff-f60f93f674b3";
    string[] splitLineResult = line.Trim().Split('"');
    var list = new List<string[]>();
    for (int i = 0; i < splitLineResult.Length; i++)
    {
        if (i % 2 == 0) 
        {
            list.Add(splitLineResult[i].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        }
        else 
        {
            list.Add(new string[] { splitLineResult[i] });
        }
    }
    var finalList = list.SelectMany(x=>x).ToList();

and for SelectMany method, you can refer MS documentation https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.selectmany?view=netframework-4.8对于 SelectMany 方法,您可以参考 MS 文档https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.selectmany?view=netframework-4.8

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

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