Except using two List [duplicate] - c#

This question already has answers here:
Using Linq Except not Working as I Thought
(5 answers)
Closed 21 days ago.
I have two list that I want to get the different. So because CustomerId 1 is in both I only want to return CustomerId 2. I am using Exceptbut I a returning CustomerId 1 and 2 any help would be great
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
List<Participants> Participants1 = new List<Participants>();
Participants vm1 = new Participants();
vm1.CustomerId = 1;
vm1.FirstName = "Bill";
vm1.LastName= "Jackson";
Participants1.Add(vm1);
List<Participants> Participants2 = new List<Participants>();
Participants vm2 = new Participants();
vm2.CustomerId = 2;
vm2.FirstName = "Steve";
vm2.LastName= "Jackson";
Participants vm3 = new Participants();
vm3.CustomerId = 1;
vm3.FirstName = "Bill";
vm3.LastName= "Jackson";
Participants2.Add(vm2);
Participants2.Add(vm3);
var inFirstOnly = Participants2.Except(Participants1);
foreach(Participants item in inFirstOnly){
Console.WriteLine(item.CustomerId);
}
}
public class Participants
{
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}

To only return CustomerId 2, you need to implement a custom equality comparer to compare objects based on the CustomerId property instead of the default comparison which compares references.
public class ParticipantsComparer : IEqualityComparer<Participants>
{
public bool Equals(Participants x, Participants y)
{
return x.CustomerId == y.CustomerId;
}
public int GetHashCode(Participants obj)
{
return obj.CustomerId.GetHashCode();
}
}
Usage:
var inFirstOnly = Participants2.Except(Participants1, new ParticipantsComparer());

Related

How to get generic method parameter property name in C#? [duplicate]

This question already has answers here:
How can I get the name of a variable passed into a function?
(23 answers)
Is it possible to get VALUE from nameof(VALUE)?
(3 answers)
Closed 1 year ago.
The expected result is to get the method parameter T property Name. Here is my code,
I have tried few suggested workarounds to make use of class ABC typeof(ABC).GetProperties - didn't get the expected result.
public class ABC
{
public string Name { get; set; }
public int RecordCount { get; set; }
public decimal Total { get; set; }
public DateTime CreatedDate { get; set; }
}
public void ExecuteMain()
{
var item = new ABC
{
Name = "TestUser A",
RecordCount = 10,
Total = 100.20m,
CreatedDate = DateTime.Now
};
AddTest<string>(item.Name);
AddTest<int>(item.RecordCount);
AddTest<decimal>(item.Total);
AddTest<DateTime>(item.CreatedDate);
}
private string AddTest<T>(T field)
{
var resultName = nameof(field); // should return as "Name"
var resultValue = field.ToString(); // this returns "TestUser A" which is correct
//Record Count, Total, CreatedDate to add later
return $"Name = {resultName}:{resultValue}";
}
Expecting result in this line
var resultName = nameof(field); // should return as "Name"
I don't know why you are trying to do that, but this is how you should write it :
using System.Reflection;
public class ABC
{
public string Name { get; set; }
public int RecordCount { get; set; }
public decimal Total { get; set; }
public DateTime CreatedDate { get; set; }
}
public void ExecuteMain()
{
var item = new ABC
{
Name = "TestUser A",
RecordCount = 10,
Total = 100.20m,
CreatedDate = DateTime.Now
};
AddTest(item.GetType().GetProperty(nameof(item.Name)), item);
AddTest(item.GetType().GetProperty(nameof(item.RecordCount)), item);
AddTest(item.GetType().GetProperty(nameof(item.Total)), item);
AddTest(item.GetType().GetProperty(nameof(item.CreatedDate)), item);
}
private string AddTest(PropertyInfo prop, object o)
{
var resultName = prop.Name; // should return as "Name"
var resultValue = prop.GetValue(o); // this returns "TestUser A" which is correct
//Record Count, Total, CreatedDate to add later
return $"Name = {resultName}:{resultValue}";
}
However, Reflection is slow to run.
If it's just to have the name, you could do much simpler :
public void ExecuteMain()
{
var item = new ABC
{
Name = "TestUser A",
RecordCount = 10,
Total = 100.20m,
CreatedDate = DateTime.Now
};
AddTest(nameof(item.Name), item.Name);
AddTest(nameof(item.RecordCount), item.RecordCount);
AddTest(nameof(item.Total), item.Total);
AddTest(nameof(item.CreatedDate), item.CreatedDate);
}
private string AddTest(String resultName, object resultValue)
{
return $"Name = {resultName}:{resultValue}";
}

How to return a specified Json format in c#

Hi all I am trying to build a quiz application using angular JS, I am having two tables Questions and Answers and the code is as follows
public class Question
{
public int QuestionID { get; set; }
public string QuestionName { get; set; }
public List<Options> Options = new List<Options>();
}
public class Options
{
public int AnswerId { get; set; }
public int QuestionID { get; set; }
public string Answer { get; set; }
public bool isAnswer { get; set; }
}
public static class QuizDetails
{
public static string GetQuiz()
{
Dictionary<int, List<Question>> displayQuestion = new Dictionary<int, List<Question>>();
//List<Quiz> quiz = new List<Quiz>();
//Options op1 = new Options();
dbDataContext db = new dbDataContext();
var v = (from op in db.QUESTIONs
join pg in db.ANSWERs on op.QUESTION_ID equals pg.QUESTION_ID
select new { Id = op.QUESTION_ID, Name = op.QUESTION_NAME, pg.ANSWER_ID, pg.QUESTION_ID, pg.ANSWER_DESCRIPTION, pg.CORRECT_ANSWER }).ToList();
return JsonConvert.SerializeObject(v);
}
}
This is my reference code for building the application
http://www.codeproject.com/Articles/860024/Quiz-Application-in-AngularJs, how can I return the JSON format as per the code written in the JS files can some one help me
Right now GetQuiz returns a string that represents an object. Your client doesn't really know what the string contains, it just handles it as a normal string.
You can either return it in another way, for example:
return new HttpResponseMessage
{
Content = new StringContent(
JsonConvert.SerializeObject(v),
System.Text.Encoding.UTF8,
"application/json")
};
If you want to keep returning it as a string you will have to manually deserialize it in the client:
var object = angular.fromJson(returnedData);

How to bypass or implement IComparable

I get the below error and I can't understand why and how to get past it (or implement icomparable).
I'm trying to get the property Group from the object that has the biggest count of Group using Max().
public class Program
{
private static void Main(string[] args) {
var list = new List<Foo>();
for (var i = 0; i < 10; i++) {
list.Add(new Foo());
if (i == 5) {
var foo = new Foo() {
Group = { "One", "Two", "Three" }
};
list.Add(foo);
}
}
var maxGroup = list.Max(x => x.Group); //throws error
}
}
public class Foo {
public Guid Id { get; } = new Guid();
public int Field1 { get; set; }
public int Field2 { get; set; }
public int Field3 { get; set; }
public int Field4 { get; set; }
public List<string> Group { get; set; } = new List<string>();
}
at least one object must implement icomparable
I'm trying to get the property Group from the object that has the longest list
You don't want to do Max for that. Simply order by the length of the list, and take the first one:
Foo res = list.OrderByDescending(x => x.Group.Count).FirstOrDefault();
if (res != null) {
List<string> longestList = res.Group;
}

Linq At least one object must implement IComparable

I am trying to order a List of Entities that contains another list of Entities. I have implemented IComparable for all entities and still get the exception. All of the examples I have seen address the issue where you have one list and you order by a given field in that list but not where you have a list of lists. This issue is happening for Linq to Objects per below and also for Linq to Entities. What am I missing?
[TestClass]
public class OrderBy
{
[TestMethod]
public void OrderByTest()
{
var hobbies = new Collection<Hobby> { new Hobby { HobbyId = 1, Name = "Eating" }, new Hobby() { HobbyId = 2, Name = "Breathing" } };
var p1 = new Person
{
PersonId = 1,
Name = "A",
PersonHobbies = new Collection<PersonHobby> { new PersonHobby() { PersonHobbyId = 1}}
};
var p2 = new Person
{
PersonId = 2,
Name = "Z",
PersonHobbies = new Collection<PersonHobby> { new PersonHobby() { PersonHobbyId = 2 }}
};
var people = new List<Person> { p1, p2 };
var pplEnumerable = people.AsEnumerable();
pplEnumerable = pplEnumerable.OrderByDescending(r => r.PersonHobbies.OrderByDescending(p => p.Hobby.Name));
foreach (var person in pplEnumerable)
{
Console.WriteLine(person.Name);
}
}
public class Person : IComparable
{
public int PersonId { get; set; }
public string Name { get; set; }
public virtual ICollection<PersonHobby> PersonHobbies { get; set; }
public int CompareTo(object obj)
{
if (obj == null) return 1;
var otherPerson = obj as Person;
return PersonId.CompareTo(otherPerson.PersonId);
}
}
public class PersonHobby : IComparable
{
public int PersonHobbyId { get; set; }
public int HobbyId { get; set; }
public virtual Person Person{ get; set; }
public int PersonId { get; set; }
public virtual Hobby Hobby { get; set; }
public int CompareTo(object obj)
{
if (obj == null) return 1;
var otherPersonHobby = obj as PersonHobby;
return PersonHobbyId.CompareTo(otherPersonHobby.PersonHobbyId);
}
}
public class Hobby : IComparable
{
public int HobbyId { get; set; }
public string Name { get; set; }
public int CompareTo(object obj)
{
if (obj == null) return 1;
var otherHobby = obj as Hobby;
return HobbyId.CompareTo(otherHobby.HobbyId);
}
}
}
You cannot apply ordering to lists by default. You need to write up a custom class (sort of EquatableList etc.) or use LINQ Except & Intersect operators to compare lists.
But based on your comment, if you're looking for the LINQ equivalent of:
select * from Person p join PersonHobby ph
on ph.PersonId = p.PersonId join Hobby h
on h.HobbyId = ph.HobbyId order by h.Name
then that can be achieved as:
var query = people.SelectMany(p => p.PersonHobbies)
.Join(hobbies, ph => ph.HobbyId, h => h.HobbyId,
(ph, h) => new
{
Person = ph.Person, PersonHobby = ph, Hobby = h
})
.OrderBy(r => r.Hobby.Name);
basically we join person, person hobbies and hobby on the keys, and project all columns and sort it by the hobby.name field, as mentioned in your SQL.

compare properties in classes of list in class

What I've got are two classes which each contain Lists of Classes with propperties of different types. The first list is an updated version of the second and i need to find all differences (deleted/added classes in lists and updated classes).
public class ClassOfKb
{
public List<Data> KbData {get;set;}
public List<Info> KbInfo {get;set;}
}
class Data
{
public Guid ID {get;set}
public byte[] file {get;set}
public string name {get;set}
}
class Info
{
public Guid ID {get;set}
public string text {get;set}
public DateTime date {get;set}
}
ClassOfKb KbA = new ClassOfKb();
ClassOfKb KbB = new ClassOfKb();
first KbA and KbB will be filled from the same DataSet, then i delete, add and modify some of KbA Child-Classes.
now i need to compare KbA with KbB to find out where the differences are. i need the ID of deleted or added classes in KbA and the exact changes of modified Child-Classes properties. How would i do this? Preffered with Linq.
I suggest that create two comparers one for Data and one for Info
class DataComparer : IEqualityComparer<Data>
{
public bool Equals(Data x, Data y)
{
//logic to compare x to y and return true when they are equal
}
public int GetHashCode(Data d)
{
//logic to return a hash code
}
}
class InfoComparer : IEqualityComparer<Info>
{
public bool Equals(Info x, Info y)
{
//logic to compare x to y and return true when they are equal
}
public int GetHashCode(Info i)
{
//logic to return a hash code
}
}
The you can use Intersect and Except LINQ methods
IEnumerable<Data> DataInAandNotInB = KbA.KbData.Except(KbB.KbData,new DataComparer());
IEnumerable<Info> InfoInAandInB = KbA.KbInfo.Intersect(KbB.KbInfo,new InfoComparer ());
For simplicity, I skipped comparison of the byte array and DateTime data membes, only left the IDs and the string data members, but to add them you will need some small modification.
The test is very-very basic, but shows all three of the changes options:
static void Main(string[] args)
{
ClassOfKb KbA = new ClassOfKb();
ClassOfKb KbB = new ClassOfKb();
// Test data --------
Data data1 = new Data() { ID = Guid.NewGuid(), name = "111" };
Data data2 = new Data() { ID = Guid.NewGuid(), name = "222" };
Data data2_changed = new Data() { ID = data2.ID, name = "222_changed" };
Data data3 = new Data() { ID = Guid.NewGuid(), name = "333" };
Info info1 = new Info() { ID = Guid.NewGuid(), text = "aaa" };
Info info2 = new Info() { ID = Guid.NewGuid(), text = "bbb" };
Info info2_changed = new Info() { ID = info2.ID, text = "bbb_changed" };
Info info3 = new Info() { ID = Guid.NewGuid(), text = "ccc" };
KbA.KbData.Add(data1);
KbA.KbData.Add(data2);
KbA.KbInfo.Add(info1);
KbA.KbInfo.Add(info2);
KbB.KbData.Add(data2_changed);
KbB.KbData.Add(data3);
KbB.KbInfo.Add(info2_changed);
KbB.KbInfo.Add(info3);
// end of test data ---------
// here is the solution:
var indexes = Enumerable.Range(0, KbA.KbData.Count);
var deleted = from i in indexes
where !KbB.KbData.Select((n) => n.ID).Contains(KbA.KbData[i].ID)
select new
{
Name = KbA.KbData[i].name,
KbDataID = KbA.KbData[i].ID,
KbInfoID = KbA.KbInfo[i].ID
};
Console.WriteLine("deleted:");
foreach (var val in deleted)
{
Console.WriteLine(val.Name);
}
var added = from i in indexes
where !KbA.KbData.Select((n) => n.ID).Contains(KbB.KbData[i].ID)
select new
{
Name = KbB.KbData[i].name,
KbDataID = KbB.KbData[i].ID,
KbInfoID = KbB.KbInfo[i].ID
};
Console.WriteLine("added:");
foreach (var val in added)
{
Console.WriteLine(val.Name);
}
var changed = from i in indexes
from j in indexes
where KbB.KbData[i].ID == KbA.KbData[j].ID &&
(//KbB.KbData[i].file != KbA.KbData[j].file ||
KbB.KbData[i].name != KbA.KbData[j].name ||
//KbB.KbInfo[i].date != KbA.KbInfo[j].date ||
KbB.KbInfo[i].text != KbA.KbInfo[j].text
)
select new
{
Name = KbA.KbData[j].name,
KbDataID = KbA.KbData[j].ID,
KbInfoID = KbA.KbInfo[j].ID
};
Console.WriteLine("changed:");
foreach (var val in changed)
{
Console.WriteLine(val.Name);
}
Console.ReadLine();
}
}
public class ClassOfKb
{
public List<Data> KbData = new List<Data>();
public List<Info> KbInfo = new List<Info>();
}
public class Data
{
public Guid ID { get; set; }
public byte[] file { get; set; }
public string name { get; set; }
}
public class Info
{
public Guid ID { get; set; }
public string text { get; set; }
public DateTime date { get; set; }
}

Categories

Resources