Подтвердить что ты не робот

Самый быстрый способ сравнить два общих списка для различий

Что является самым быстрым (и наименее ресурсоемким) для сравнения двух массивных ( > 50 000 элементов) и, как результат, имеют два списка, как показано ниже:

  • элементы, которые отображаются в первом списке, но не во втором
  • которые отображаются во втором списке, но не в первом

В настоящее время я работаю со списком или IReadOnlyCollection и решая эту проблему в запросе linq:

var list1 = list.Where(i => !list2.Contains(i)).ToList();
var list2 = list2.Where(i => !list.Contains(i)).ToList();

Но это не так хорошо, как хотелось бы. Любая идея сделать это быстрее и менее ресурсоемкой, поскольку мне нужно обработать много списков?

4b9b3361

Ответ 1

Используйте Except:

var firstNotSecond = list1.Except(list2).ToList();
var secondNotFirst = list2.Except(list1).ToList();

Я подозреваю, что есть подходы, которые на самом деле были бы немного быстрее, чем этот, но даже это будет значительно быстрее, чем ваш подход O (N * M).

Если вы хотите объединить их, вы можете создать метод с вышеприведенным, а затем оператор return:

return !firstNotSecond.Any() && !secondNotFirst.Any();

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

Например, для списков [1, 2, 2, 2, 3] и [1] результат "элементы в list1, но не list2" в исходном коде будет [2, 2, 2, 3]. С моим кодом это будет просто [2, 3]. Во многих случаях это не будет проблемой, но об этом стоит знать.

Ответ 2

Более эффективным будет использование Enumerable.Except:

var inListButNotInList2 = list.Except(list2);
var inList2ButNotInList = list2.Except(list);

Этот метод реализуется с использованием отложенного выполнения. Это означает, что вы могли бы написать, например:

var first10 = inListButNotInList2.Take(10);

Он также эффективен, поскольку он внутренне использует Set<T> для сравнения объектов. Он работает, сначала собирая все различные значения из второй последовательности, а затем передавая результаты первого, проверяя, что они не были замечены раньше.

Ответ 3

Если вы хотите, чтобы результаты были нечувствительными к регистру, будет работать следующее:

List<string> list1 = new List<string> { "a.dll", "b1.dll" };
List<string> list2 = new List<string> { "A.dll", "b2.dll" };

var firstNotSecond = list1.Except(list2, StringComparer.OrdinalIgnoreCase).ToList();
var secondNotFirst = list2.Except(list1, StringComparer.OrdinalIgnoreCase).ToList();

firstNotSecond будет содержать b1.dll

secondNotFirst будет содержать b2.dll

Ответ 4

Enumerable.SequenceEqual Method

Определяет, равны ли две последовательности согласно средству сравнения на равенство. MS.Docs

Enumerable.SequenceEqual(list1, list2);

Это работает для всех примитивных типов данных. Если вам нужно использовать его на пользовательских объектах, вам нужно реализовать IEqualityComparer

Определяет методы для поддержки сравнения объектов на равенство.

IEqualityComparer Interface

Определяет методы для поддержки сравнения объектов на равенство. MS.Docs для IEqualityComparer

Ответ 5

Не для этой проблемы, но вот какой-то код для сравнения списков для равных и не! идентичные объекты:

public class EquatableList<T> : List<T>, IEquatable<EquatableList<T>> where    T : IEquatable<T>

/// <summary>
/// True, if this contains element with equal property-values
/// </summary>
/// <param name="element">element of Type T</param>
/// <returns>True, if this contains element</returns>
public new Boolean Contains(T element)
{
    return this.Any(t => t.Equals(element));
}

/// <summary>
/// True, if list is equal to this
/// </summary>
/// <param name="list">list</param>
/// <returns>True, if instance equals list</returns>
public Boolean Equals(EquatableList<T> list)
{
    if (list == null) return false;
    return this.All(list.Contains) && list.All(this.Contains);
}

Ответ 6

попробуйте следующим образом:

var difList = list1.Where(a => !list2.Any(a1 => a1.id == a.id))
            .Union(list2.Where(a => !list1.Any(a1 => a1.id == a.id)));

Ответ 7

Я использовал этот код для сравнения двух списков с миллионом записей.

Этот метод не займет много времени

    //Method to compare two list of string
    private List<string> Contains(List<string> list1, List<string> list2)
    {
        List<string> result = new List<string>();

        result.AddRange(list1.Except(list2, StringComparer.OrdinalIgnoreCase));
        result.AddRange(list2.Except(list1, StringComparer.OrdinalIgnoreCase));

        return result;
    }

Ответ 8

using System.Collections.Generic;
using System.Linq;

namespace YourProject.Extensions
{
    public static class ListExtensions
    {
        public static bool SetwiseEquivalentTo<T>(this List<T> list, List<T> other)
            where T: IEquatable<T>
        {
            if (list.Except(other).Any())
                return false;
            if (other.Except(list).Any())
                return false;
            return true;
        }
    }
}

Иногда вам нужно только знать, отличаются ли два списка, а не каковы эти различия. В этом случае рассмотрите возможность добавления этого метода расширения в ваш проект. Обратите внимание, что ваши перечисленные объекты должны реализовывать IEquatable!

Использование:

public sealed class Car : IEquatable<Car>
{
    public Price Price { get; }
    public List<Component> Components { get; }

    ...
    public override bool Equals(object obj)
        => obj is Car other && Equals(other);

    public bool Equals(Car other)
        => Price == other.Price
            && Components.SetwiseEquivalentTo(other.Components);

    public override int GetHashCode()
        => Components.Aggregate(
            Price.GetHashCode(),
            (code, next) => code ^ next.GetHashCode()); // Bitwise XOR
}

Каким бы ни был класс Component, методы, показанные здесь для Car должны быть реализованы практически одинаково.

Очень важно отметить, как мы написали GetHashCode. Чтобы правильно реализовать IEquatable, Equals и GetHashCode должны работать со свойствами экземпляра логически совместимым способом.

Два списка с одинаковым содержимым по-прежнему являются разными объектами и будут давать разные хэш-коды. Поскольку мы хотим, чтобы эти два списка обрабатывались как равные, мы должны позволить GetHashCode создать одинаковое значение для каждого из них. Мы можем сделать это путем делегирования хеш-кода каждому элементу в списке и использования стандартного побитового XOR для их объединения. XOR не зависит от порядка, поэтому не имеет значения, сортируются ли списки по-разному. Имеет значение только то, что они не содержат ничего, кроме эквивалентных членов.

Примечание: странное имя подразумевает тот факт, что метод не учитывает порядок элементов в списке. Если вы заботитесь о порядке элементов в списке, этот метод не для вас!

Ответ 9

Если нужен только комбинированный результат, это тоже будет работать:

var set1 = new HashSet<T>(list1);
var set2 = new HashSet<T>(list2);
var areEqual = set1.SetEquals(set2);

где T - тип элемента списков.

Ответ 10

Может быть, это смешно, но работает для меня.

string.Join( ", List1)!= string.Join(" ", List2)

Ответ 11

Это лучшее решение, которое вы нашли

var list3 = list1.Where(l => list2.ToList().Contains(l));

Ответ 12

Я думаю, что это простой и легкий способ сравнить два списка элемент за элементом

x=[1,2,3,5,4,8,7,11,12,45,96,25]
y=[2,4,5,6,8,7,88,9,6,55,44,23]

tmp = []


for i in range(len(x)) and range(len(y)):
    if x[i]>y[i]:
        tmp.append(1)
    else:
        tmp.append(0)
print(tmp)