简体   繁体   English

IEnumerable集合的串联C#

[英]Concatenation of IEnumerable collections C#

I have 2 results of a Linq query, with which i want to do do some string operations and concatenate. 我有2个Linq查询的结果,我想使用它们执行一些字符串操作并进行连接。

Result 1 which is the names of enabled checkboxes from group1, obtained by 结果1是从组1获得的已启用复选框的名称,由

var selectedCarPosts = grpBox1MCar.Controls.OfType<CheckBox>()
.Where(c => c.Checked).OrderBy(c => c.Name).Select(c => c.Name);

which yields Result 1: 结果为1:

NearMainGate
NearMP5WestGate

Result 2 which is the names of enabled checkboxes from group2, obtainedby 结果2是group2中启用的复选框的名称,由

var selectedDtTypeCars = gbDataTypeMCars.Controls.OfType<CheckBox>()
.Where(c => c.Checked).OrderBy(c => c.Name).Select(c => c.Name);

which yields Result2: 产生Result2:

WindDir
WindVel

From both results would like to get a concatenated list as follows: (Result3) 从这两个结果想得到一个串联列表,如下所示:(Result3)

C.NearMainGate
C.NearMP5WestGate
C.WindDirNearMainGate
C.WindDirNearMP5WestGate
C.WindVelNearMainGate
C.WindVelNearMP5WestGate

These form columns in a dynamic sql query later. 这些在以后的动态sql查询中形成列。

I have the following code to accomplish this step by step: 我有以下代码逐步完成此操作:

var s1 = selectedCarPosts.Select(s => "C." + s); //the first 2 items in Result3
//Now to get the rest, by inserting Result2 string in each of the first 2 items of Result3
IEnumerable<string> selCarPostsArrWithC = new string[]{};
IEnumerable<string> s2 = new string[]{};
foreach (var type in selectedDtTypeCars)
{
   selCarPostsArrWithC = s1.Select(s => s.Insert(2, type));//C.WindDirNearMainGate C.WindDirNearMP5WestGate in FIRST iteration and so on
   s2 = s2.Concat(selCarPostsArrWithC);// as soon as the SECOND iteration starts, the previous s2 list is overwritten with the subsequent result in selCarPostsArrWithC 
 }

The problem here is that during code debugging, I noticed, that as soon as I tap F10 key just after the foreach line, before actually reaching the foreach block, the the previous values in s2 is overwritten with the subsequent result in selCarPostsArrWithC already. 这里的问题是,在代码调试过程中,我注意到,只要在foreach行之后点击F10键,然后才实际到达foreach块,则s2中的先前值将被selCarPostsArrWithC中的后续结果覆盖。 Explained below 解释如下

For the first iteration s2 has result. 对于第一次迭代,结果为s2。

[0] "C.WindDirNearMainGate"
[1] "C.WindDirNearMP5WestGate"

At the beginning of second iteration before entering inside the foreach block 在第二次迭代的开始之前,先进入foreach块

s2 already resets to new values with WindVel some how: s2已经通过WindVel重置为新值,方法如下

[0] "C.WindVelNearMainGate"
[1] "C.WindVelNearMP5WestGate"

Please could any one assist what am I doing wrong? 请任何人能协助我做错了什么吗? How can i accomplish Result3 in bold, for the IEnumerable list? 如何为IEnumerable列表以粗体显示Result3?

Enumerable.Select doesn't do anything important when you call it, it merely sets things up so that the requested work will be performed later as desired. Enumerable.Select在您调用它时没有做任何重要的事情,它只是进行设置,以便稍后根据需要执行请求的工作。

So when you write 所以当你写

selCarPostsArrWithC = s1.Select(s => s.Insert(2, type));

this doesn't call string.Insert yet. 这不会调用string.Insert了。 string.Insert is only called when you (or your debugger) later starts iterating over selCarPostsArrWithC . 仅当您(或调试器)稍后开始对selCarPostsArrWithC迭代时才调用string.Insert

Normally, that doesn't matter, except for performance if you iterate over the enumerable multiple times. 通常情况下,这并不重要,除非性能需要多次迭代。 However, here, because string.Insert is called later than you expect, the arguments that you pass to it are also evaluated later than you expect. 但是,在这里,由于string.Insert的调用比预期的要晚,因此传递给它的参数的计算比预期的要晚。 You only have a single type variable, and that variable already holds the next value by the time it gets read. 您只有一个type变量,并且该变量在被读取时已经保存了下一个值。

In general, you can either solve this by creating a new variable per iteration, that captures the value of type as seen during that iteration: 通常,您可以通过在每次迭代中创建一个新变量来解决此问题,该变量捕获该迭代期间看到的type值:

foreach (var type in selectedDtTypeCars)
{
  var type_ = type;
  selCarPostsArrWithC = s1.Select(s => s.Insert(2, type_));
  s2 = s2.Concat(selCarPostsArrWithC);
}

(Nowadays, C# already does this behind the scenes for foreach , but you may need to write it out like this if using an older compiler.) (现在,C#已经在foreach幕后这样做了,但是如果使用旧的编译器,则可能需要这样写出来。)

Or, alternatively, perform all of the evaluations directly inside the loop body: 或者,也可以直接在循环体内执行所有评估:

foreach (var type in selectedDtTypeCars)
{
  selCarPostsArrWithC = s1.Select(s => s.Insert(2, type)).ToList();
  s2 = s2.Concat(selCarPostsArrWithC);
}

Although in that case, it would be better to just make s2 a List<string> , and call its AddRange method. 尽管在这种情况下,最好将s2设为List<string>并调用其AddRange方法。

Basically you have a list of prefixes, and a list of suffixes. 基本上,您有一个前缀列表和一个后缀列表。 (Note: I skimmed your code, and I couldn't find where you got the C. that was appended to each of the values.) (注意:我浏览了您的代码,但找不到在每个值后面附加C.的位置。)

For every prefix, you need a suffix. 对于每个前缀,您都需要一个后缀。

This is the use of SelectMany() 这是SelectMany()的用法

I simplified your code, because you gave quite a bit of code. 我简化了代码,因为您给出了很多代码。 But here's what I came up with: 但是这是我想出的:

    var location = new[]
    {
      "NearMainGate", 
      "NearMP5WestGate"
    };

    var modifier = new[]
    {
      "WindDir", 
      "WindVel"
    };

    var lambdaResult = modifier.SelectMany(s => location.Select(l => string.Format("{0}{1}{2}", "C.", s, l)));

    var queryResult =
        from m in modifier
        from l in location
        select string.Format("{0}{1}{2}", "C.", m, l);

Note that there's two solutions: a linq query syntax, and linq lambda syntax. 请注意,有两种解决方案:linq查询语法和linq lambda语法。

In this situation, I think the query syntax is cleaner and easier to read, but to each their own. 在这种情况下,我认为查询语法更简洁易读,但各有千秋。

And here's a fiddle with proof of functionality: https://dotnetfiddle.net/Z61RsI 这是功能证明的小提琴: https : //dotnetfiddle.net/Z61RsI

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

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