Получение "diff" между двумя массивами в С#?

Скажем, у меня есть эти два массива:

var array1 = new[] {"A", "B", "C"};
var array2 = new[] {"A", "C", "D"};

Я хотел бы получить различия между ними. Я знаю, что могу написать это всего в нескольких строках кода, но хочу, чтобы у меня не было встроенной функции языка или метода расширения LINQ.

В идеале я получаю следующие три результата:

  • Элементы не в массиве1, а в массиве2 ( "D" )
  • Элементы не в массиве2, а в массиве 1 ( "В" )
  • Элементы, которые находятся в обоих

Спасибо заранее!

Ответ 1

Если у вас есть LINQ, вы можете использовать Except и Distinct. Сеты, заданные вами в вопросе, соответственно:

- array2.Except(array1)
- array1.Except(array2)
- array1.Intersect(array2)

Ответ 2

из MSDN 101 образцов LINQ....

public void Linq52() {
    int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
    int[] numbersB = { 1, 3, 5, 7, 8 };

    IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB);

    Console.WriteLine("Numbers in first array but not second array:");
    foreach (var n in aOnlyNumbers) {
        Console.WriteLine(n);
    }
}

Ответ 3

Ниже приведены эталоны методов расширения LINQ. Результаты были получены при разработке реальной программы.

Тесты: 2 списка (lst1 и lst2) каждый примерно 250000 объектов. Каждый объект (класс Key) содержит строку и целое число. Во втором списке в основном содержатся те же записи, что и первый, но некоторые новые записи добавляются, а некоторые удаляются.

Я тестировал метод расширения Except.

var except = lst2.Except(lst1);

Список lst = except.ToList();

Эти 2 строки подготовили 600 пунктов списка "новых дополнений". Я приурочил его, используя объект StopWatch. Скорость поражает: 220 мс. Компьютер, который я использовал, отнюдь не является "скорейшим Гонзалесом". Core 2 Duo T7700 - 2,4 ГГц.

Примечание:

Вот класс Key, который реализует IEquatable i-face.

public class Key : IEquatable<Key>
{
    public int Index { get; private set; }
    public string Name { get; private set; }

    public Key(string keyName, int sdIndex)
    {
        this.Name = keyName;
        this.Index = sdIndex;
    }

 // IEquatable implementation
    public bool Equals(Key other)
    {
        //Check whether the compared object is null.
        if (Object.ReferenceEquals(other, null)) return false;
        //Check whether the compared object references the same data.
        if (Object.ReferenceEquals(this, other)) return true;
        //Check whether the products' properties are equal.
        return Index.Equals(other.Index) && Name.Equals(other.Name);
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.
    public override int GetHashCode()
    {
        //Get hash code for the name field if it is not null.
        int hashKeyName = Name == null ? 0 : Name.GetHashCode();
        //Get hash code for the index field.
        int hashKeyIndex = Index.GetHashCode();
        //Calculate the hash code for the Key.
        return hashKeyName ^ hashKeyIndex;
    }
}

Ответ 4

Мне приходилось делать подобные вещи с очень большими наборами данных. Если вы имеете дело с несколькими тысячами или около того, используйте материал Linq, так как он намного яснее. Но если вы знаете, что ваши массивы предварительно отсортированы, запуск такого слияния может сделать это значительно быстрее, поскольку он только пропускает данные и не требует выделения столько памяти, сколько версия Linq.

int iA = 0;
int iB = 0;
List<int> inA = new List<int>();
List<int> inB = new List<int>();
List<int> inBoth = new List<int>();
while (iA < numbersA.Length && iB < numbersB.Length)
{
    if (numbersA[iA] < numbersB[iB])
    {
        inA.Add(numbersA[iA++]);
    }
    else if (numbersA[iA] == numbersB[iB])
    {
        inBoth.Add(numbersA[iA++]);
        ++iB;
    }
    else
    {
        inB.Add(numbersB[iB++]);
    }
}
while (iA < numbersA.Length)
{
    inA.Add(numbersA[iA++]);
}
while (iB < numbersB.Length)
{
    inB.Add(numbersB[iB++]);
}

Опять же, это действительно необходимо, только если вы имеете дело со сотнями тысяч значений.

Ответ 5

Другое решение будет как ниже

int[] arr1 = new int[] { 45, 26, 99, 55, 36 };
int[] arr2 = new int[] { 45, 26, 99, 20, 36 };

var res = arr1.Union(arr2).Except(arr1.Intersect(arr2));

Ответ 6

I used the above logic to solve a problem.

public static void Main()
    {
        int t = Convert.ToInt32(Console.ReadLine());

        for (int i = 0; i < t; i++)
        {
            int s = Convert.ToInt32(Console.ReadLine());
            int[] a = new int[s];
            int[] b = new int[s];
            string numbersLine = Console.ReadLine();
            string[] numbers = numbersLine.Split(new char[] { ' ' });
            a = Array.ConvertAll(numbers, Int32.Parse);
            numbersLine = Console.ReadLine();
            numbers = numbersLine.Split(new char[] { ' ' });
            b = Array.ConvertAll(numbers, Int32.Parse);

            IEnumerable<int> aOnlyNumbers = a.Except(b);
            IEnumerable<int> bOnlyNumbers = b.Except(a);
            if ((a.Sum() != b.Sum()) || (aOnlyNumbers.Count() != 0 && bOnlyNumbers.Count() != 0))
            {
                if (aOnlyNumbers.Count() == 1 && bOnlyNumbers.Count() == 1)
                {
                    int numberfroma = aOnlyNumbers.Single();
                    int numberfromb = bOnlyNumbers.Single();
                    if (numberfroma < numberfromb)
                    {
                        Console.WriteLine(numberfromb - numberfroma + " 1");
                    }
                    else
                    {
                        Console.WriteLine(numberfroma - numberfromb + " 2");
                    }
                }
                else if ((a.Sum() != b.Sum()) && (aOnlyNumbers.Count() < 1 || bOnlyNumbers.Count() < 1))
                {
                    if (a.Sum() < b.Sum())
                    {
                        Console.WriteLine(b.Sum() - a.Sum() + " 1");
                    }
                    else
                    {
                        Console.WriteLine(a.Sum() - b.Sum() + " 2");
                    }
                }
                else if (aOnlyNumbers.Count() >1 || bOnlyNumbers.Count() >1)
                {
                    Console.WriteLine("No");
                }
            }
            else if (aOnlyNumbers.Count() == 0 && bOnlyNumbers.Count() == 0)
                {
                Console.WriteLine("Yes");
            }


        }