Empty string comparison is failing - c#

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.

Related

Check if two instances of same class have same data in 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;

Refactor a method that it can handle multiple types?

I have the following class:
public class Disciplines
{
public int Id { get; set; }
public string Discipline { get; set; }
public bool IsChecked { get; set; }
}
My project has several view models that use that class to create a checkbox group in the form of:
public List<Disciplines> DisciplinesCBG { get; set; }
I'm saving the checkbox selections to the database as a comma separated string, and then splitting the string on the comma to re display as checkboxes:
public static UserProfileViewModel DisciplinesStringToCheckboxGroup(UserProfileViewModel model)
{
string[] disciplineArray = model.Disciplines.Split(',');
for (int i = 0; i < model.DisciplinesCBG.Count; i++)
{
string currentValue = model.DisciplinesCBG[i].Discipline;
if(Array.IndexOf(disciplineArray, currentValue) > -1)
{
model.DisciplinesCBG[i].IsChecked = true;
}
}
return model;
}
My question is, how can I write the method to be usable for other ViewModel types in addition to UserProfileViewModel? For example I have a view model called RegisterViewModel that uses the same public List<Disciplines> DisciplinesCBG { get; set; } that I would like to be able to use the same method as above without having to just copying it and change the signature. I'm assuming that it is possible?
You can create an interface that has Disciplines and DisciplinesCBG property and then implement it in each classes that you want to apply.
interface IHasDiciplines
{
string Disciplines { get; set; }
List<Disciplines> DisciplinesCBG { get; set; }
}
class UserProfileViewModel : IHasDiciplines
{
public string Disciplines { get; set; }
public List<Disciplines> DisciplinesCBG { get; set; }
}
public static IHasDiciplines DisciplinesStringToCheckboxGroup(IHasDiciplines model)
{
string[] disciplineArray = model.Disciplines.Split(',');
for (int i = 0; i < model.DisciplinesCBG.Count; i++)
{
string currentValue = model.DisciplinesCBG[i].Discipline;
if(Array.IndexOf(disciplineArray, currentValue) > -1)
{
model.DisciplinesCBG[i].IsChecked = true;
}
}
return model;
}

How do I correctly add mixes of different interfaces to different classes in C#?

I am trying to develop an API for some assessment software that will allow me to create questions consisting of the question text, multiple choice text and the choice index of the correct answer.
All questions are worth 10 points and the question can only be answered once.
For QuestionTypeA however, the user can change the number of retries and QuestionTypeB, the user can change both the number of retries and the score.
The reason for the CommonFunctions interface is so that I don't have to duplicate QuestionText, AddChoice and SetAnswer in each of the QuestionType interfaces.
But this does then leave me with empty interfaces, which I am not sure is correct?
Also, to instantiate an object I have to write
QuestionTypeA QTA = (QuestionTypeA)new Question();
I would rather the Question class dealt with the cast so that the user can then just type:
QuestionTypeA QTA = new Question();
How can achieve this?
Thanks
Andrew
public interface IRetryable
{
int Retries { set; get; }
}
public interface IScoreable
{
int Score { set; get; }
}
public interface CommmonFunctions
{
string QuestionText { set; get; }
void AddChoice(string ChoiceText);
int SetAnswer { set; get; }
}
public interface QuestionTypeA : CommmonFunctions, IRetryable
{
}
public interface QuestionTypeB : CommmonFunctions, IRetryable, IScoreable
{
}
public interface QuestionTypeC : CommmonFunctions
{
}
class Question : CommmonFunctions
{
private List<string> Choices;
public Question()
{
Choices = new List<string>();
Retries = 1;
Score = 10;
}
public string QuestionText { set; get; }
public void AddChoice(string ChoiceText)
{
Choices.Add(ChoiceText);
}
public int SetAnswer { set; get; }
public int Retries { set; get; }
public int Score { set; get; }
}
It seems you are over-thinking things...
Just keep it simple.
var question1 = new QuestionTypeA();
var question2 = new QuestionTypeB();
public interface IRetryable
{
int Retries { set; get; }
}
public interface IScoreable
{
int Score { set; get; }
}
public abstract class Question
{
private List<string> choices = new List<string>();
public string QuestionText { set; get; }
public int SetAnswer { set; get; }
public void AddChoice(string choiceText)
{
choices.Add(choiceText);
}
}
public class QuestionTypeA : Question, IRetryable
{
public QuestionTypeA()
{
Retries = 1;
}
public int Retries { set; get; }
}
public class QuestionTypeB : Question, IScoreable
{
public QuestionTypeB()
{
Score = 0;
}
public int Score { set; get; }
}
Thanks ASh for your response.
I guess it would make sense to incorporate in them in to the interface.
I now need to add another interface (IShuffle) to QuestionTypeA as below.
interface IShuffable
{
void Shuffle();
}
public class QuestionTypeA : Question, IRetryable, IShuffable
{
public QuestionTypeA()
{
Retries = 1;
}
public int Retries { set; get; }
public void Shuffle()
{
// Code to implement shuffling the choices
}
}
Shuffle has nothing to do with QuestionType B or C, so Ideally I would like to hide this method from instances of QuestionType B and C so that it doesn't appear in intellisense.
Any attempt to call the shuffle method on instances of either QuestionTypeB or C, should then result in a standard compiler error i.e "QuestionTypeB does not contain a definition for shuffle ...".
Would it be better to use interfaces for this solution given the above? or something else?
Thanks Andrew
since all question have at least score 10 and 0 or more retries, why not include that info in the common interface like this?
public interface CommmonFunctions
{
string QuestionText { set; get; }
void AddChoice(string ChoiceText);
int SetAnswer { set; get; }
int Score { set; get; }
bool ScoreReadonly {get;}
int Retries { set; get; }
bool RetriesReadonly {get;}
}
ScoreReadonly and RetriesReadonly show if score or retries count can be changed outside class:
class Question : CommmonFunctions
{
private List<string> Choices;
public Question()
{
Choices = new List<string>();
_retries = 1;
_score = 10;
}
public string QuestionText { set; get; }
public void AddChoice(string ChoiceText)
{
Choices.Add(ChoiceText);
}
public int SetAnswer { set; get; }
private int _retries;
public int Retries
{
get{ return _retries; }
set
{
if (!RetriesReadonly)
_retries = value;
}
}
private int _score;
public int Score
{
get{ return _score; }
set
{
if (!ScoreReadonly)
_score = value;
}
}
public virtual bool ScoreReadonly {get{return false;}}
public virtual bool RetriesReadonly {get{return false;}}
}
UPDATE
public interface IShuffable
{
void Shuffle();
}
class QuestionTypeA : Question, IShuffable
{
// question of type A can't change score
public override bool ScoreReadonly { get {return true;}}
public void Shuffle()
{
// Code to implement shuffling the choices
}
}
class QuestionTypeB : Question {}

how can I swap two child entity values

I have an entity called "Space" and inside it has "Images". Images has an ordering property that is an int. I'm trying to see if there is an easy linq that can be made to swap the ordering values.
public class Space
{
public int SpaceId { get; set; }
public virtual ICollection<SpaceImage> Images { get; set; }
}
public class SpaceImage
{
public int SpaceImageId { get; set; }
public byte[] Image { get; set; }
public byte[] ImageThumbnail { get; set; }
public string ContentType { get; set; }
public int Ordering { get; set; }
}
ex.
an image might have ordering 3 and another will have 6, I want to swap these two numbers for each of these images
public void Swap(int spaceId, int old, int new)
{
//swap 3 and 6 for the ordering value for the two spaceImages that contain these values where spaceId is spaceId
}
In general, LINQ would be used for querying. You could use it to find the appropriate SpaceImage instances, then set the values appropriately:
// Assuming this is a method in the Space class
public void Swap(int oldOrder, int newOrder)
{
var oldInst = this.Images.FirstOrDefault(si => si.Ordering == oldOrder);
var newInst = this.Images.FirstOrDefault(si => si.Ordering == newOrder);
if (oldInst != null && newInst != null)
{
oldInst.Ordering = newOrder;
newInst.Ordering = oldOrder;
}
else
{
// There weren't matching images - handle that case here
}
}

Entity Framework adding too many records

EDIT: See the bottom of this question for the working code.
I have two tables, Patients and Drugs, that I am updating with a data feed. I get a current list of patients, then iterate through and update or insert records as appropriate. This works without issue.
The trouble comes when I iterate through that patient's current medications. I end up getting multiple copies of the original patient. Drug records are transferred as expected (the records themselves don't change so new records are inserted and existing records ignored). I end up with the original patient record (inserted from UpdatePatients() below) and then one additional patient record for each medication record. Each medication record ends up with a distinct PatientId.
Class definitions:
public class Patient
{
public int PatientId { get; set; }
[Required]
public int FacilityNumber { get; set; }
[Required]
public int PatNo { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int Age { get; set; }
[Required]
public string Gender { get; set; }
[Required]
public DateTime VentStart { get; set; }
[Required]
public DateTime VentEnd { get; set; }
[Required]
public DateTime AdmitDate { get; set; }
public DateTime? DischargeDate { get; set; }
}
public class Drug
{
public int DrugId { get; set; }
[Required]
public int DrugDDI { get; set; }
[Required]
public int OrderId { get; set; }
[Required]
public string DrugName { get; set; }
[Required]
public DateTime DispenseDate { get; set; }
[Required]
public double UnitsDispensed { get; set; }
[ForeignKey("Patient")]
public int PatientId { get; set; }
public virtual Patient Patient { get; set; }
}
Offending code:
private static void UpdatePatients()
{
var Patients = DB2Patient.GetPatients();
foreach (Patient p in Patients)
{
using (var PatientContext = new VAEContext())
{
var ExistingPatientRecord = PatientContext.Patients.FirstOrDefault(
ep => ep.PatNo == p.PatNo
);
if (ExistingPatientRecord != null)
{
ExistingPatientRecord.VentEnd = p.VentEnd;
ExistingPatientRecord.DischargeDate = p.DischargeDate;
PatientContext.SaveChanges();
}
else
{
PatientContext.Patients.Add(p);
PatientContext.SaveChanges();
}
}
UpdateDrugs(p);
}
}
private static void UpdateDrugs(Patient p)
{
var Drugs = DB2Drug.GetDrugs(p.PatNo);
foreach (Drug d in Drugs)
{
using (var DrugContext = new VAEContext())
{
var ExistingDrugRecord = DrugContext.Drugs.FirstOrDefault(
ed => ed.DrugDDI == d.DrugDDI &&
ed.DispenseDate == d.DispenseDate &&
ed.OrderId == d.OrderId
);
if (ExistingDrugRecord == null)
{
d.Patient = p;
DrugContext.Drugs.Add(d);
DrugContext.SaveChanges();
}
}
}
}
EDIT: Working code:
private static void UpdatePatients()
{
var Patients = DB2Patient.GetPatients();
using (var db = new VAEContext())
{
foreach (Patient p in Patients)
{
var ExistingPatientRecord = db.Patients.FirstOrDefault(
ep => ep.PatNo == p.PatNo
);
if (ExistingPatientRecord != null)
{
ExistingPatientRecord.VentEnd = p.VentEnd;
ExistingPatientRecord.DischargeDate = p.DischargeDate;
}
else
{
db.Patients.Add(p);
}
UpdateDrugs(p, db);
}
db.SaveChanges();
}
}
private static void UpdateDrugs(Patient p, VAEContext ctx)
{
var Drugs = DB2Drug.GetDrugs(p.PatNo);
foreach (Drug d in Drugs)
{
var ExistingDrugRecord = ctx.Drugs.FirstOrDefault(
ed => ed.DrugDDI == d.DrugDDI &&
ed.DispenseDate == d.DispenseDate &&
ed.OrderId == d.OrderId
);
if (ExistingDrugRecord == null)
{
d.Patient = p;
ctx.Drugs.Add(d);
}
}
}
Why new context every time something needs to be inserted? Both methods UpdatePatients and UpdateDrugs are private, you can use the same context for all linked operations and I'm sure you won't get the duplicates:
private static void UpdateDrugs(Patient p, VAEContext context)
...
Also there's probably no need to save on every drug, doing so likely decreases performance and doesn't do much in terms of data integrity. Consider saving the context changes once per linked updates (say after UpdateDrugs is called in UpdatePatients)
Other than that you can check out the ObjectContext.Attach and related methods on how to link the Patient object to your newly created Drugs context instance
http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.attach.aspx

Categories