Come confrontare due elenchi di oggetti basati su informazioni parziali di proprietà?

Diciamo che vuoi confrontare due elenchi di oggetti basati su una versione troncata (penso che sia la parola) di una proprietà DateTime:

public class MyObject { public DateTime SomeDate {get;set;} } 

Confronta gli elenchi normalmente:

 bool didItWork = myFirstList.Intersect(MySecondList).Any(); 

Tutto bene e bene qui eccetto che ho bisogno di fare questo controllo basato sulla proprietà DateTime sopra:

 bool didItWork = myFirstLIst.Intersect(MySecondList).Any(someIntuitivePredicate); 

Come puoi vedere, non so quale sia il predicato intuitivo.

E per un kicker voglio tagliare la sezione Time di SomeDate quando faccio il confronto:

 dateWithoutTime = myObject.SomeDate.Date; 

Il tempo non è importante solo la data effettiva.

Vedendoti smarcata la risposta, mi prenderò una brutta piega, tuttavia le risposte sono davvero dei buoni sforzi, ma il risultato della tua vaga definizione del problema. Anche il tuo commento “Se ci sono elementi in entrambe le liste che non esistono nell’altro” è un po ‘imbarazzato. Non sto cercando di licenziarti, ma tienilo a mente. Quando si ha a che fare con operazioni di set, bisogna fare un passo indietro e pensare seriamente a ciò che si vuole realizzare. In questo caso interpreterò il tuo objective e, se ciò non è corretto, dovresti aggiornare la tua domanda con una definizione del problema più chiaramente definita:

Voglio verificare che per ogni elemento di myFirstList ci sia un elemento in mySecondList con lo stesso SomeDate.Date e viceversa.

Se stai troncando il tempo da una data, allora vorrei ipotizzare che potrebbero esserci casi in cui ci sono due articoli con la stessa data. Se così non fosse, ci sono metodi più semplici che adottano approcci come unire o intersecare gli elenchi e verificare che i risultati abbiano un conteggio uguale a quello degli originali (che verifica che tutti gli elementi abbiano trovato una corrispondenza). Le altre risposte che usano join o intersect non funzionano, perché usano .Any() che restituirà true se solo uno degli elementi corrisponde, piuttosto che tutto.

.All si assicureranno che tutti gli articoli in una lista soddisfino alcuni criteri. In questo caso, assicurati che ogni articolo abbia una corrispondenza nella seconda lista.

 bool isListEqual = myFirstList.All(x=> mySecondList.Select(y=>y.SomeDate.Date).Contains( x.SomeDate.Date) ) isListEqual = isListEqual && mySecondList.All(x=> myFirstList.Select(y=>y.SomeDate.Date).Contains( x.SomeDate.Date) ) 

Facciamo entrambe le indicazioni per garantire che non ci siano elementi nella seconda lista senza un elemento corrispondente nel primo.

Se sapessimo che non c’erano duplicati, un altro approccio sarebbe quello di unire gli elenchi e contare i risultati per assicurarsi che corrispondano agli originali. O potremmo semplicemente eliminare i duplicati per generare liste distinte. È inoltre ansible utilizzare SetEquals di hashset o SequenceEquals di IEnumerable. SequenceEquals è meglio se sai che i tuoi risultati sono già in un ordine particolare.

  var firstDates = myFirstList.Select(l=>l.SomeDate.Date).Distinct().OrderBy(d=>d).ToList(); var secondDates = mySecondList.Select(l=>l.SomeDate.Date).Distinct().OrderBy(d=>d).ToList(); bool isListEqual = firstDates.SequenceEqual(secondDates); 

Penso che la cosa più importante che dovresti prendere da questo, è che l’approccio dipende da quali supposizioni puoi fare riguardo ai tuoi dati di input.

Questa domanda copre diversi approcci e il duplicato è anche collegato a:

Controlla se due liste sono uguali

Per quanto posso vedere, hai due opzioni:

  1. Implementare un IEqualityComparer personalizzato e passarlo al sovraccarico Intersect che accetta unComponente IEquality .

O

  1. Simula Intersect con nidificato Any :

     bool didItWork = myFirstList.Any(item1 => mySecondList.Any(item2 => item1.SomeDate.Date == item2.SomeDate.Date)); 

    Ovviamente, item1.SomeDateDate == item2.SomeDate.Date può essere sostituito da un predicato arbitrario.

    Ecco una versione alternativa per coloro che preferiscono la syntax della query LINQ:

     bool didItWork = (from item1 in myFirstList from item2 in mySecondList where item1.SomeDate.Date == item2.SomeDate.Date).Any(); 

È ansible utilizzare un overload del metodo Intersect che accetta anche un’implementazione di IEqualityComparer come input:

 bool didItWork = myFirstList.Intersect(MySecondList, new MyEqualityComparer()).Any(); // ... public class MyEqualityComparer : IEqualityComparer { public bool Equals(MyObject x, MyObject y) { return x.SomeDate.Date == y.SomeDate.Date; } public int GetHashCode(MyObject x) { return x.SomeDate.Date.GetHashCode(); } }