Check if two instances of same class have same data in C# - c#

I'm trying to validate if both my objects have the same values.
here's my class
public class myclass
{
public List<c1> List1{ get; set; }
public List<c2> List2{ get; set; }
public List<c3> List3{ get; set; }
}
public class c1
{
public int Number{ get; set; }
public string Name{ get; set; }
public bool IsAvailable{ get; set; }
}
public class c2
{
public int Id{ get; set; }
public string Text{ get; set; }
public GUID Guid{ get; set; }
}
public class c3
{
public int? Age{ get; set; }
public string Role{ get; set; }
public bool IsDeleted{ get; set; }
}
I have 2 instances of this class and I want to compare the data between both the instances and check if they both are the same or not.
I've tried Serializing both the objects and comparing but that's not working as the items in the list can be in a different order.
I've also tried getting HashSet of individual lists and checking if they are equal.
var s1 = new HashSet<c1>(list1);
var s2= new HashSet<c1>(list2);
return s1.SetEquals(s2);

One solution would be to first order the lists using a standard order, like numeric or alphabetic depending on the types, and then trying something like this
if (myclassInstance1.list1.SequenceEqual(myclassInstance2.list1))
{
//Repeat the cycle 2 more times and then //your code
}
Since this one works comparing the sequence you need to first order the lists and to do that you can maybe use this
EDIT: This is the documentation for the list.sequenceEquals() method

The best way to do this is if you explicitly implement the models with IEqualityComparer in .NET.
using System;
using System.Collections.Generic;
public class Program
{
public class MyClass
{
public List<C1> C1List { get; set; }
public List<C2> C2List { get; set; }
}
public class C1 : IEqualityComparer<C1>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Equals(C1 x, C1 y)
{
if(string.Equals(x.FirstName, y.FirstName, StringComparison.OrdinalIgnoreCase)
&& string.Equals(x.LastName, y.LastName, StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
public int GetHashCode(C1 c)
{
return c.FirstName.Length * c.LastName.Length;
}
}
public class C2 : IEqualityComparer<C2>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Equals(C2 x, C2 y)
{
if(string.Equals(x.FirstName, y.FirstName, StringComparison.OrdinalIgnoreCase)
&& string.Equals(x.LastName, y.LastName, StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
public int GetHashCode(C2 c)
{
return c.FirstName.Length * c.LastName.Length;
}
}
}
The IEqualityComparer will give you full control on "the parameters based on which you call 2 objects equal".
As for the above implementation, I have considered the 2 objects are equal if the FirstName and the LastName are same.

Try to order the list,and then compare the data in it:
List<c1> l1 = list1.OrderBy(c => c.Number).ToList();
List<c1> l2 = list2.OrderBy(c => c.Number).ToList();
bool equalValue = true;
if (l1.Count() == l2.Count()) {
for (int i = 0; i < l1.Count(); i++){
if (l1[i].IsAvailable != l2[i].IsAvailable || l1[i].Number != l2[i].Number || l1[i].Name != l2[i].Name)
{
equalValue = false;
break;
}
}
}
else {
equalValue = false;
}
return equalValue;

Related

How to manually map a List of object to a list of DTO?

I have these:
public class FamilyHead
{
public Guid HeadId { get; set; }
public string Name { get; set; }
}
public class Citizen
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
// more properties
[ForeignKey("FamilyHead")]
public Guid HeadId { get; set; }
public virtual FamilyHead FamilyHead { get; set; }
}
public class CitizenDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
public Guid HeadId
public string HeadName { get; set; }
}
I can manually map it via extension method if it is a single instance:
public static CitizenDTO ToDTO(this Citizen citizen)
{
if (citizen == null) return null;
return new CitizenDTO {
Id = citizen.Id,
Name = citizen.Name,
HeadId = citizen.HeadId,
HeadName = citizen.FamilyHead.Name
}
}
var dto = aCitizen.ToDTO();
But how to map a list of citizens? I think Select() might do the work but I only know how to do it if the model and the dto have a same structure. Like this example:
IEnumerable<int> integers = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<string> strings = integers.Select(i => i.ToString());
So how to map a list of it?
You can use Linq Select() as you used for string in your question, no need to write long extension method
IEnumerable<CitizenDTO> dto = citizens.Select(x => x.ToDTO());
I found the answer before finishing my question. Just iterate through the list and add mapped DTO to it. Silly me
// Extension method
public static IEnumerable<CitizenDTO> ToDTO(this IEnumerable<Citizen> citizens)
{
if (citizen == null) return null;
var dto = new List<CitizenDTO>();
foreach(var citizen in citizens) {
dto.Add(citizen.ToDTO());
}
return dto;
}
// How to use
IEnumerable<CitizenDTO> result = listOfCitizens.ToDTO();

Empty string comparison is failing

Currently writing a simple reservation. Right now I have a multidimensional string array that holds the passengers name and I am trying to iterate through that array and see whether there are any open seats so I know whether or not to add them to a waiting list.
// Check how many seats are taken
for (int i = 0; i <= nameArray.GetUpperBound(0); i++)
{
for (int j = 0; j <= nameArray.GetUpperBound(1); j++)
{
if (nameArray[i, j] == "")
{
seatsFilled--;
}
else
{
seatsFilled++;
}
}
}
For some reason when I debug, I notice that this line
if (nameArray[i, j] == "")
Doesn't do anything at all and gets skipped over despite there being no names in the array. I cannot for the life of me figure out why. Any suggestions?
One of the reason i can see is the comparison may have the whitespace. Try this
if(string.IsNullOrWhiteSpace(nameArray[i, j]))
I would do something like this:
First I would create some interfaces and models that would define the structure of the seat. Make sure to account for seat restrictions.
public interface ISeat
{
int RowNumber { get; }
string SeatLetter { get; }
PassangerModel Passenger { get; }
}
We want to allow some of the seats to be restricted based on passenger age and height. Hard coding that into each seat is nasty so instead I created a SeatRestriction class that has a predicate in it. This predicate will take the passenger model in and return a result. So for example you could create a SeatRestriction that checked a passengers height or age to make sure they can open emergency doors.
public class SeatRestriction
{
public Predicate<PassangerModel> Restriction { get; private set; }
public SeatRestriction(Predicate<PassangerModel> restriction)
{
Restriction = restriction;
}
}
The passenger model can actually be much more verbose than this. I'm assuming here no dietary needs. Maybe this is a reservation system for Spirit Airlines.
public class PassangerModel
{
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string CreditCardName { get; set; }
public string CreditCardNumber { get; set; }
public string CreditCardExpiration { get; set; }
public string CreditCardSecurityPin { get; set; }
}
Next We come to our seat class. This class allows us to see if a passenger is assigned to the seat. Take note that it also asserts prior to adding the passenger to the seat if the passenger meets the restrictions, if any.
public interface IRestrictedSeat
{
List<SeatRestriction> Restrictions { get; }
bool AssertQualifiedPassenger(PassangerModel passenger);
}
public class Seat : ISeat, IRestrictedSeat
{
public bool IsSeatReserved { get { return Passenger != null; } }
public int RowNumber { get; private set; }
public string SeatLetter { get; private set; }
public PassangerModel Passenger { get; private set; }
public List<SeatRestriction> Restrictions { get; private set; }
public Seat(int rowNumber, string seatLetter)
{
Restrictions = new List<SeatRestriction>();
RowNumber = rowNumber;
SeatLetter = seatLetter;
}
public bool TryAddPassenger(PassangerModel passanger)
{
if (AssertQualifiedPassenger(passanger))
{
Passenger = passenger;
return true;
}
else
{
return false;
}
}
public bool AssertQualifiedPassenger(PassangerModel passenger)
{
foreach(SeatRestriction restriction in Restrictions)
{
if (!restriction.Restriction(passenger))
{
return false;
}
}
return true;
}
}
Finally we get to the row. Our row knows how manys seats it has and what its number is. You should be able to add seats to it and then call GetAvailableSeats to get the seats that are left in this row.
public class SeatRow
{
public int TotalSeats { get; private set; }
public int RowNumber { get; private set; }
public List<Seat> Seats { get; private set; }
public SeatRow(int seatsInRow, int rowNumber)
{
TotalSeats = seatsInRow;
RowNumber = rowNumber;
}
public bool TryAddSeatToRow(Seat seat)
{
if(Seats.Count <= TotalSeats && seat.RowNumber == RowNumber)
{
Seats.Add(seat);
return true;
}
else
{
return false;
}
}
public IEnumerable<Seat> GetAvailableSeats()
{
return Seats.Where(seat => seat.IsSeatReserved == false);
}
}
The long and short of this answer is there's a million ways to solve CIS problems and to not rely on stack overflow while you're in school/learning. Good luck and welcome to the club :-)
if (nameArray[i, j] == "")
Doesn't do anything at all and gets skipped over despite there being no names in the array.
That line is inside a loop that iterates through the items in the array. If the array is empty then this will never get executed.

LINQ Intersection not working

I have two list that i want to compare. In one i have a small amount of objects and in the other im sure i have the objects from the first list plus others.
Im trying to do an intersection to get the objects from the second list that are in my first list.To do that i have the object inside the two list is of type
public class ReportDataImportant : ReportData
{
public String IdTitular { get; set; }
public String Identificacion { get; set; }
public String IndicadorPersona { get; set; }
public String Titular { get; set; }
public decimal Porcentaje { get; set; }
public int Cotitulares { get; set; }
public String IndicadorNacionalidad { get; set; }
public String Nacionalidad { get; set; }
}
I have also a comparer class like this:
public class ReportDataComparer : IEqualityComparer<ReportDataImportant>
{
public bool Equals(ReportDataImportant x, ReportDataImportant y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) ||
Object.ReferenceEquals(y, null))
return false;
return x.Identificacion.Equals(y.Identificacion);
}
public int GetHashCode(ReportDataImportant obj)
{
if (Object.ReferenceEquals(obj, null)) return 0;
return obj.Identificacion.GetHashCode();
}
}
An to make the intersection i call it with this expresion :
var reult = _list1.Intersect(List2, new ReportDataComparer()).ToList();
However im not getting the result im expecting. Does somebody know what is happening?

How to group multiple lists using LINQ - Sum and GroupBy

I have three generic lists and I am trying to combine and get them into one (List<One>). I am not sure how to use LINQ group by on different lists. I want to group by AccountCode, AccountDate, and SalesCode; and sum the amount.
public class One
{
public string AccountCode { get; set; }
public DateTime AccountDate { get; set; }
public string SalesCode { get; set; }
public decimal? Amount { get; set; }
}
public class Two
{
public string AccountCode { get; set; }
public DateTime AccountDate { get; set; }
public string SalesCode { get; set; }
public decimal? Amount { get; set; }
}
public class Three
{
public string AccountCode { get; set; }
public DateTime AccountDate { get; set; }
public string SalesCode { get; set; }
public decimal? Amount { get; set; }
}
List<One> oneList = new List<One>();
List<Two> twoList = new List<Two>();
List<Three> threeList = new List<Three>();
This is the sample query I have, which is not working. Note: I have not included List<Three>.
from first in oneList
join second in twoList
on first.AccountCode equals second.AccountCode
where
(first.AccountDate.Date == second.AccountDate.Date && first.SalesCode == second.SalesCode)
select new
{
first.AccountCode,
first.AccountDate,
first.SalesCode
first.Amount,
second.Amount
}).Distinct()
group bill by new { bill.AccountCode, bill.AccountDate, bill.SalesCode }
into groupedList
select new
{
groupedList.Key.UAN,
groupedList.Key.AccountDate,
Amount = groupedList.Sum(a => a.Amount)
};
As mentioned in the comment, the first thing you'll need is a common type so that the 3 lists can be joined into a single list. That could be a base class or an interface as I've shown here.
public interface IAccount
{
string AccountCode { get; set; }
DateTime AccountDate { get; set; }
string SalesCode { get; set; }
decimal? Amount { get; set; }
}
public class One : IAccount
{
// ...
}
public class Two : IAccount
{
// ...
}
public class Three : IAccount
{
// ...
}
Once that's in place, then it's easy to combine your 3 lists into one like this:
var allList = oneList.Cast<IAccount>().Union(twoList).Union(threeList);
From there, the group by becomes much simpler as well. When using LINQ to group by multiple fields, you'll want an IEqualityComparer class that looks like this:
public class AccountComparer : IEqualityComparer<IAccount>
{
public bool Equals(IAccount x, IAccount y)
{
return x.AccountCode == y.AccountCode &&
x.AccountDate == y.AccountDate &&
x.SalesCode == y.SalesCode;
}
public int GetHashCode(IAccount obj)
{
return (obj.AccountCode + obj.AccountDate + obj.SalesCode).GetHashCode();
}
}
The group by call is then one line:
var groups = allList.GroupBy(a => a, new AccountComparer());
Alternatively, you could create an AccountKey class that only has the 3 key fields and return that from the keySelector lambda. That feels a little cleaner, but is a bit more code.
From there, you can select the sums like this:
var amountSums = from g in groups
select new
{
g.Key.AccountCode,
g.Key.AccountDate,
g.Key.SalesCode,
Amount = g.Sum(a => a.Amount)
};

Contains with Linq

I have class "Estimation", this class has a property "EstimationItems" (the type is IList)
public class EstimationItem
{
public virtual int Id { get; set; }
public virtual Product Product { get; set; }
public virtual int Quantity { get; set; }
public virtual decimal Price { get; set; }
}
public class Product
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
public virtual string Name { get; set; }
}
When I have an instance of "Estimation", I'd like to know if "EstimationItems" contain a product with the code "MyCode".
Using this :
List<EstimationItem> items = new List<EstimationItem>();
// Add items
int searchedCode = 1
if(items.Any(i => i.Product.Code == searchedCode))
{
// Contained
}
You can use Any():
bool hasMyCode = yourEstimation.EstimationItems.Any(
item => item.Product.Code == "MyCode");
Enumerable.Any Method determines whether any element of a sequence satisfies a condition.
Boolean result = estimationItems.Any(x => x.Product.Code == "MyCode");
var query = from ei in EstimationItems where ei.Product.Code == "MyCode" select ei;

Categories