C #: Как сравнить две коллекции (System.Collection.Generic.List <T>), используя Linq / Lambda? - PullRequest
2 голосов
/ 05 марта 2012

У меня есть две коллекции String как

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

Мне нужно сравнить два списка и сделать второй список как

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

Примечание: Оба списка будут содержать одинаковое количество элементов, а длина каждого элемента будет одинаковой.

Сравнение похоже на

  1. Если элемент mth в l_lstOne имеет 'X' в n-й позиции, n-ную позицию mth в l_lstTwo следует заменить на 'X'.

Пример * * тысяча двадцать-один

    l_lstOne            l_lstTwo        Output

      100                 000             000
      1X0                 110             1X0
      X11                 100             X00

Итак, для решения этой проблемы я использовал вложенный цикл, вот мой исходный код,

 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;
        }   

Этот код работает нормально, но дело в том, что для его выполнения требуется больше времени, т. Е. Почти 600 миллисекунд для обработки 200000 элементов и каждого из них длиной 16.

И, кроме того, мне нужен метод Linq или Lambda для решения этой проблемы. Поэтому, пожалуйста, помогите мне сделать это. Заранее спасибо.

Ответы [ 3 ]

5 голосов
/ 05 марта 2012

LINQ вам здесь не поможет;LINQ не предназначен для изменения коллекций.

Вы можете существенно ускорить ваш код, создав char[] вместо string;сейчас вы создаете 3,2 миллиона string объектов из-за +=.

Вместо этого вы можете написать

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);
2 голосов
/ 05 марта 2012

Вы можете сделать это с помощью следующего оператора в .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]));
2 голосов
/ 05 марта 2012

М-ч, если я правильно понимаю, слова в l_lstOne действуют как маска для слов в l_lstTwo, где маска прозрачна, если это не X. Как насчет этого:

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

Zip - это метод расширения Linq , доступный в .NET 4, в котором элементы двух списков объединяются в виде zip. Внешний почтовый индекс в основном создает пары слов для итерации, а второй создает маску (берут все символы из второго слова, если только у слова 1 нет X в этой позиции).

Также обратите внимание, что это создает новую последовательность строк, а не заменяет их в l_lstTwo - это способ действий Linq.

...