简体   繁体   中英

C# : How to compare two collections (System.Collection.Generic.List<T>) using Linq/Lambda?

I'm having two collections of String like

 List<String> l_lstOne = new List<String> { "100", "1X0", "X11", "XXX" }, 
    l_lstTwo = new List<String> { "000", "110", "100", "000" };

I need to compare the two lists and make the second list like

    { "000", "1X0", "X00", "XXX" }

Note: Both the list will contain same numbe of elements and the length of each element will be same.

The comparision is like

  1. If an mth element in l_lstOne have an 'X' in nth position, the the nth position of the mth in l_lstTwo should be replaced by 'X'.

Example

    l_lstOne            l_lstTwo        Output

      100                 000             000
      1X0                 110             1X0
      X11                 100             X00

So, to solve this i used nested for loop , here is my source code,

 for (int l_nIndex = 0; l_nIndex < l_lstTwo.Count; l_nIndex++)
        {
            String l_strX = String.Empty;

            for (int l_nInnerIndex = 0; l_nInnerIndex < l_lstTwo[l_nInnerIndex].Length; l_nInnerIndex++)
            {
                l_strX += l_lstOne[l_nIndex][l_nInnerIndex] == 'X' ? 'X' : l_lstTwo[l_nIndex][l_nInnerIndex];
            }
            l_lstTwo[l_nIndex] = l_strX;
        }   

This code is working fine, but the thing is, its taking more time to execute, ie almost 600 milliseconds to process 200000 elements and each of length 16.

And moreover i need a Linq or Lambda method to resolve this. So please help me to do this. Thanks in advance.

LINQ will not help you here; LINQ is not meant to modify collections.

You can make your code substantially faster by building a char[] instead of a string ; right now, you're building 3.2 million string objects because of the += .

Instead, you can write

char[] l_strX = new char[l_lstTwo[l_nInnerIndex].Length];

for (int l_nInnerIndex = 0; l_nInnerIndex < l_lstTwo[l_nInnerIndex].Length; l_nInnerIndex++)
{
    l_strX[l_nInnerIndex] = l_lstOne[l_nIndex][l_nInnerIndex] == 'X' ? 'X' : l_lstTwo[l_nIndex][l_nInnerIndex];
}
l_lstTwo[l_nIndex] = new string(l_strX);

Mh, if I understand it correctly the words in l_lstOne act as a mask for the words in l_lstTwo where the mask is transparent unless it's an X . How about this:

l_lstOne.Zip(l_lstTwo, 
    (w1, w2) => new String(w1.Zip(w2, (c1, c2) => c1 == 'X' ? c1 : c2).ToArray())))

Zip is a Linq extension method available from .NET 4 on which combines the elements of two lists like a zip. The outer zip basically creates the word pairs to iterate over and the second one creates a the mask (take all characters from the second word unless word one has an X in that position).

Also note that this creates a new sequence of strings rather than replacing the ones in l_lstTwo - that's the Linq way of doing things.

You could do it with the following statement in .NET 3.5

    IEnumerable <String> result =
        Enumerable.Range(0, l_lstOne.Count)
            .Select(i => Enumerable.Range(0, l_lstOne[i].Length)
                .Aggregate(string.Empty, (innerResult, x) => innerResult += l_lstOne[i][x] == 'X' ? 'X' : l_lstTwo[i][x]));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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