10

Using C# with LINQ, how can I merge two lists of different objects, say, Seminar and Conference? They have some common and some different fields/properties and do not share unique id.

class Seminar
{
   int id,
   DateTime joinDate,
   string name
}

class Conference
{
   Guid confNumber,
   DateTime joinDate
   Type type
}

I have a list of:

List<Seminar>
List<Conference>

I need to merge them into a super List:

List<Object>

A code snippet would be great help.

Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
user3410713
  • 161
  • 1
  • 1
  • 7
  • 1
    Please clarify *merge*. Posting the code you tried would also be a good idea. – Frédéric Hamidi Jul 04 '14 at 18:27
  • 1
    Yes, a code snippet would definitely be a great help – dotnetom Jul 04 '14 at 18:29
  • 2
    Your definition of merge is far more important than our definition. If they have common properties, then ideally they share an `interface` that would facilitate the merge. – pickypg Jul 04 '14 at 18:32
  • @user, you're still not disclosing *how* you want the lists to be merged, and the code you provided is not valid C# and contains no attempt at solving your problem. – Frédéric Hamidi Jul 04 '14 at 18:37
  • @user Please do not purposely re-add spelling mistakes when users suggest edits. – AStopher Jul 04 '14 at 18:41
  • Thanks! Have edited the original post. Pls see it. – user3410713 Jul 04 '14 at 18:41
  • @zybox, please don't modify code in questions (or answers) in your suggested edits. I won't roll it back now that the questioner has updated his post further, but I would have otherwise. – Frédéric Hamidi Jul 04 '14 at 18:42
  • 1
    What are you trying to accomplish? Why do you *want* heterogeneous objects in the same collection? I think you have a design problem, you're just not aware of it yet. – Daniel Mann Jul 04 '14 at 18:43
  • @FrédéricHamidi I did not modify the code, the code had issues (the `.` was not needed, for one thing), there is also no such thing as a `supurt list`. Another user modified the code, and you have not complained directly to them, please don't 'single out' people. – AStopher Jul 04 '14 at 18:44
  • @zybox, that's because [your edit](http://stackoverflow.com/review/suggested-edits/5222663) was improved by Abbas. When I originally voted to reject it, it was changing `DateTime` into `datetime` in the code. *Oh, actually that was in [another one](http://stackoverflow.com/revisions/24579324/6). How easy it is to get edits approved these days...* – Frédéric Hamidi Jul 04 '14 at 18:46
  • @FrédéricHamidi Weird, I never changed (nor noticed) that `DateTime` was changed to `datetime`, I simply put the code into code-blocks. Perhaps a bug with SO's code formatter? – AStopher Jul 04 '14 at 18:47
  • I have a need that I need to comibine both records of Seminar and Conference; order them by joinDate (= common field in the both objects) in ascending order; need to compare target point in every date in sequence; and finally need to pick the date when target point is met. – user3410713 Jul 04 '14 at 18:50
  • 1
    @user, excellent. Now please post this information *in your question* (use the [edit](http://stackoverflow.com/posts/24579324/edit) link). Again, posting the code you tried would also help, otherwise at this level of complexity your question will be closed. – Frédéric Hamidi Jul 04 '14 at 18:51

3 Answers3

13

If you just want a single List<object> containing all objects from both lists, that's fairly simple:

List<object> objectList = seminarList.Cast<object>()
    .Concat(conferenceList)
    .ToList();

If that's not what you want, then you'll need to define what you mean by "merge".

Richard Deeming
  • 29,830
  • 10
  • 79
  • 151
  • Thanks lot! How to cast it back to original object to get -lets say- properties of Seninar and Conference from the combined list, in my case, objectList ? – user3410713 Jul 04 '14 at 19:24
  • I tried doing something like following:
    List combinedList = employee.Seminar.Cast()
    .Concat(employee.Conference) .ToList();

    var TotalPoint = combinedList
    .Count(x => x.Status == Completed
    && x.EndDate <= DeadLineDate);

    It did not work because x is still object type, it does not know what type it is refering to (Seminar or Conference). How to cast it back to point to a particular object while reading the properties of either Seminar or Conference ?
    – user3410713 Jul 04 '14 at 19:44
  • 3
    @user3410713: You'll need to create an interface containing the common properties that you need to read. Have both classes implement that interface, change the `.Cast()` to `.Cast()`, and replace `List` with `List`; you'll then be able to access the common properties from the combined list. – Richard Deeming Jul 04 '14 at 19:54
6

Following code works fine for me, if this is your definition of Merge

One solution

List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = new A() } };

List<Object> allS = (from x in someAs select (Object)x).ToList();
allS.AddRange((from x in someBs select (Object)x).ToList());

Where A and B are some classes as follows

class A
{
    public string someAnotherThing { get; set; }
}
class B
{
    public A something { get; set; }
}

Another Solution

List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = string.Empty } };

List<Object> allS = (from x in someAs select (Object)new { someAnotherThing = x.someAnotherThing, something = string.Empty }).ToList();
allS.AddRange((from x in someBs select (Object)new { someAnotherThing = string.Empty, something = x.something}).ToList());

Where A and B are having class definition as

class A
{
    public string someAnotherThing { get; set; }
}
class B
{
    public string something { get; set; }
}
Durgesh Chaudhary
  • 1,075
  • 2
  • 12
  • 31
  • Thanks lot! How to cast it back to original object to get -lets say- properties of Seninar and Conference from the combined list, in my case, allS? – user3410713 Jul 04 '14 at 19:25
  • I tried doing something like following:
    List combinedList = employee.Seminar.Cast()
    .Concat(employee.Conference) .ToList();

    var TotalPoint = combinedList
    .Count(x => x.Status == Completed
    && x.EndDate <= DeadLineDate);

    It did not work because x is still object type, it does not know what type it is refering to (Seminar or Conference). How to cast it back to point to a particular object while reading the properties of either Seminar or Conference ?
    – user3410713 Jul 04 '14 at 19:39
  • then Another Solution will work for you, apart form that you can also have `if (o is Seminar ){} else if(o is Conference){}` – Durgesh Chaudhary Jul 05 '14 at 04:48
1

Simple method of pure code

internal class Person
{
    public int Id { get; set; }
    public string UserName { get; set; }
}

internal class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

internal class UserPerson
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

private static void Main(string[] args)
    {
        Person[] people = new Person[3] { new Person { Id = 1, UserName = "AliUserName" }, new Person { Id = 2, UserName = "MortezaUserName" }, new Person { Id = 3, UserName = "SalarUserName" } };
        User[] users = new User[4] { new User { FirstName = "ali", LastName = "Barzegari" }, new User { FirstName = "Morteza", LastName = "Sefidi" }, new User { FirstName = "Salar", LastName = "Pirzadeh" }, new User { FirstName = "Babak", LastName = "Hasani" } };

        UserPerson[] userPeople = new UserPerson[people.Length > users.Length ? people.Length : users.Length];
        if (people.Length > users.Length)
            for (int i = 0; i < people.Length; i++)
            {
                userPeople[i] = new UserPerson
                {
                    Id = people[i].Id,
                    UserName = people[i].UserName,
                    FirstName = users.Length <= i ? "" : users[i].FirstName,
                    LastName = users.Length <= i ? "" : users[i].LastName
                };
            }
        else
            for (int i = 0; i < users.Length; i++)
            {
                userPeople[i] = new UserPerson
                {
                    Id = people.Length <= i ? 0 : people[i].Id,
                    UserName = people.Length <= i ? "" : people[i].UserName,
                    FirstName = users[i].FirstName,
                    LastName = users[i].LastName
                };
            }
        Console.ReadLine();
    }
Morteza Sefidi
  • 105
  • 1
  • 4