Pergunta

Eu gostaria de comparar o conteúdo de um par de coleções em meu método de Equals.Eu tenho um Dicionário e uma IList.Existe um método incorporado para fazer isso?

Editado:Quero comparar dois Dicionários e dois ILists, então eu acho que a igualdade significa, é claro - se os dois dicionários contêm as mesmas teclas mapeadas para os mesmos valores e, em seguida, eles são iguais.

Foi útil?

Solução

Enumerable.SequenceEqual

Determina se duas sequências são iguais comparando seus elementos usando um determinado IEqualityComparer(T).

Você não pode comparar diretamente o & lista de dicionário, mas você poderá comparar a lista de valores do Dicionário com a lista de

Outras dicas

Como outros têm sugerido e ter notado, SequenceEqual é de ordem sensível.Para resolver isso, você pode classificar o dicionário de chave (que é única, e, portanto, a classificação é sempre estável) e, em seguida, usar SequenceEqual.A expressão a seguir verifica se dois dicionários são iguais, independentemente de sua ordem interna:

dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))

EDITAR: Como apontado por Jeppe Stig Nielsen, algum objeto tiver uma IComparer<T> que é incompatível com a sua IEqualityComparer<T>, produzindo resultados incorretos.Quando utilizar chaves com um objeto, você deve especificar um correto IComparer<T> para essas chaves.Por exemplo, com a seqüência de teclas (que apresentam esse problema), você deve fazer o seguinte a fim de obter resultados corretos:

dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))

Além do mencionado SequenceEqual, que

é verdadeiro se duas listas são de igual comprimento e suas correspondentes elementos de comparação igual de acordo com um comparador

(que pode ser o padrão de comparador, isto é,um cancelado Equals())

vale a pena mencionar que, em .Net4 há SetEquals no ISet objetos, que

ignora a ordem dos elementos e quaisquer elementos duplicados.

Então, se você quer ter uma lista de objetos, mas eles não precisam estar em uma ordem específica, considere que um ISet (como um HashSet) pode ser a escolha certa.

Dê uma olhada no Enumeráveis.SequenceEqual método

var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);

.NET, não tem as ferramentas poderosas para a comparação de coleções.Eu desenvolvi uma solução simples que você pode encontrar no link abaixo:

http://robertbouillon.com/2010/04/29/comparing-collections-in-net/

Isso irá realizar uma comparação de igualdade, independentemente de ordem:

var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;

Este irá verificar se os itens foram adicionados / removidos:

var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added;   //Sally
var inbothlists = diff.Equal;   //Bob

Isto irá ver quais os itens no dicionário alterado:

var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
  Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa

Eu não sabia sobre Enumerável.SequenceEqual método (que você aprenda algo todos os dias....), mas eu ia sugerir o uso de um método de extensão;algo como isto:

    public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
    {
        if (InternalList.Count != ExternalList.Count)
        {
            return false;
        }
        else
        {
            for (int i = 0; i < InternalList.Count; i++)
            {
                if (InternalList[i] != ExternalList[i])
                    return false;
            }
        }

        return true;

    }

Curiosamente, depois de tomar 2 segundos para ler sobre SequenceEqual, parece que a Microsoft construiu a função que eu descrevi para você.

Este não é diretamente respondendo suas perguntas, mas tanto o MS' TestTools e NUnit fornecer

 CollectionAssert.AreEquivalent

o que faz muito bem o que você deseja.

Para comparar coleções, você também pode usar o LINQ. Enumerable.Intersect retorna todos os pares que são iguais.Você pode comparse dois dicionários, como este:

(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count

A primeira comparação é necessária porque dict2 pode conter todas as chaves de dict1 e mais.

Você também pode usar a pensar em variações com Enumerable.Except e Enumerable.Union que levar a resultados semelhantes.Mas pode ser usado para determinar a exata diferenças entre os conjuntos.

Como nesse exemplo:

 static void Main()
{
    // Create a dictionary and add several elements to it.
    var dict = new Dictionary<string, int>();
    dict.Add("cat", 2);
    dict.Add("dog", 3);
    dict.Add("x", 4);

    // Create another dictionary.
    var dict2 = new Dictionary<string, int>();
    dict2.Add("cat", 2);
    dict2.Add("dog", 3);
    dict2.Add("x", 4);

    // Test for equality.
    bool equal = false;
    if (dict.Count == dict2.Count) // Require equal count.
    {
        equal = true;
        foreach (var pair in dict)
        {
            int value;
            if (dict2.TryGetValue(pair.Key, out value))
            {
                // Require value be equal.
                if (value != pair.Value)
                {
                    equal = false;
                    break;
                }
            }
            else
            {
                // Require key be present.
                equal = false;
                break;
            }
        }
    }
    Console.WriteLine(equal);
}

Cortesia : https://www.dotnetperls.com/dictionary-equals

Para encomendou colecções (Lista, Matriz) usar SequenceEqual

para usar HashSet SetEquals

para o Dicionário que você pode fazer:

namespace System.Collections.Generic {
  public static class ExtensionMethods {
    public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
      if (object.ReferenceEquals(d1, d2)) return true; 
      if (d2 is null || d1.Count != d2.Count) return false;
      foreach (var (d1key, d1value) in d1) {
        if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
        if (!d1value.Equals(d2value)) return false;
      }
      return true;
    }
  }
}

(Mais otimizado solução será o uso de ordenação, mas que vai exigir IComparable<TValue>)

Não.A estrutura de coleta não tem qualquer conceito de igualdade.Se você pensar sobre isso não há maneira de comparar coleções, o que não é subjetivo.Por exemplo, comparando o IList ao seu Dicionário, teria que ser igual, se todas as chaves estavam no IList, todos os valores foram em IList ou se ambos estavam em IList?Não há nenhuma maneira óbvia de comparar essas duas coleções, sem conhecimento do que eles são para ser usado por tanto um objectivo geral do método de equals não faz sentido.

Não, porque a estrutura não sabe como comparar o conteúdo de suas listas.

Ter um olhar para este:

http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx

public bool CompareStringLists(List<string> list1, List<string> list2)
{
    if (list1.Count != list2.Count) return false;

    foreach(string item in list1)
    {
        if (!list2.Contains(item)) return false;
    }

    return true;
}

Não foi, não é e não pode ser, pelo menos eu acredito assim.A razão por trás é a coleção de igualdade é, provavelmente, um usuário definido comportamento.

Elementos de coleções não são suposto ser em uma ordem particular, embora eles não têm uma ordem, naturalmente, não é o que a comparação de algoritmos deve confiar.Digamos que você tenha dois conjuntos de:

{1, 2, 3, 4}
{4, 3, 2, 1}

Eles são iguais ou não?Você deve saber, mas eu não sei qual é o seu ponto de vista.

As coleções são conceitualmente não ordenada por padrão, até que os algoritmos fornecem as regras de classificação.A mesma coisa que o SQL server irá chamar a sua atenção é quando você está tentando fazer a paginação, ele requer que você para fornecer regras de classificação:

https://docs.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

Ainda mais duas coleções:

{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}

Novamente, eles são iguais ou não?Você me dizer ..

Elemento de repetibilidade de uma coleção desempenha o seu papel em diferentes cenários e algumas coleções, como a Dictionary<TKey, TValue> mesmo não permitir que elementos repetidos.

Eu acredito que esses tipos de igualdade são de aplicação definido e o quadro, portanto, não fornecem todas as possíveis implementações.

Bem, em geral, casos Enumerable.SequenceEqual é bom o suficiente, mas ele retorna false em caso seguinte:

var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false

Eu li algumas respostas para perguntas como esse(que você pode o google para eles) e que eu iria usar, em geral:

public static class CollectionExtensions {
    public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
        if(object.ReferenceEquals(first, second)) {
            return true;
        }

        if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
            return Enumerable.SequenceEqual(first, second);
        }

        if(first is ICollection<T> && second is ICollection<T>) {
            if(first.Count()!=second.Count()) {
                return false;
            }
        }

        first=first.OrderBy(x => x.GetHashCode());
        second=second.OrderBy(x => x.GetHashCode());
        return CollectionExtensions.Represents(first, second);
    }
}

Isso significa que uma coleção representa o outro em seus elementos, incluindo repetidas vezes, sem tomar a ordenação original em conta.Algumas notas de aplicação:

  • GetHashCode() é apenas para a ordenação não para a igualdade;Eu acho que é o suficiente, neste caso,

  • Count() será realmente não enumera a coleta e diretamente cair na propriedade implementação de ICollection<T>.Count

  • Se as referências são iguais, é apenas Boris

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top