Combining two lists of different types and sorting by date

I have a first list of such objects:

public partial class Networking :EntityBase { public virtual int NetWorkingId { get; set; } public virtual string NetWorkingParam { get; set; } public virtual System.DateTime NetWorkingDate { get; set; } } 

And I have a second list of such objects:

 public partial class PrivateNetwork :EntityBase { public virtual int PrivateNetworkId { get; set; } public virtual int ContaId { get { return _contaId; } set { if (_contaId != value) { if (Contact != null && Contact.ContaId != value) { Contact = null; } _contaId = value; } } } public virtual Nullable<System.DateTime> DateCreation { get; set; } } 

I want to collect these two lists in one and sort all the items by date.

Is it possible?

+6
source share
6 answers

This problem can be easily solved with polymorphism; use a common base class or interface for both classes that has the DateTime property that you want to sort.

Example:

 public abstract class NetworkingBase : EntityBase { public DateTime DateToSortOn { get; set; } } 

or

 public interface INetworking { public DateTime DateToSortOn { get; set; } } 

And then make your classes from NetworkingBase or implement INetworking :

 public partial class Networking : NetworkingBase { ... } public partial class PrivateNetwork : NetworkingBase { ... } 

or

 public partial class Networking : EntityBase, INetworking { ... } public partial class PrivateNetwork : EntityBase, INetworking { ... } 

Make LINQ Union or Concat , and then OrderBy in the resulting collection.

+5
source

You can do this, although it's not very pretty, and you get an IEnumerable<object> , so you need to check each element type before you can use it:

 IEnumerable<object> sorted = myNetworkingList .Concat<object>(myPrivateNetworkList) .OrderBy(n => n is Networking ? (DateTime?)((Networking)n).NetWorkingDate : ((PrivateNetwork)n).DateCreation); foreach (object either in sorted) { if (either is Networking) // Networking; do something else // PrivateNetwork; do something else } 
+5
source

What I should have asked before.,

What do you want to do after you sort them?

The answer to this can have a big impact on the potential solution.

If the answer is something like I need to display a list of dates where you only need dates in order. If so, you do not need to combine the two lists, you can get a sequence of only ordered dates and use them, for example.

 var orderedDates = networks.Select(n => n.NetworkingDate) .Union(privateNetworks.Select(n => n.DateCreation)) .OrderBy(date => date); 

If the answer is: I need to display a list of links showing a date that refers to the identifier of the object, and something to identify the type of object, then you could leave with something very similar to the above, with the Anonymous object.

 var orderedDates = networks.Select(n => new {Date = n.NetworkingDate, Id = n.NetWorkingId, NetworkType = n.GetType().Name}) .Union(privateNetworks.Select(n => new {Date = n.DateCreation, Id = n.PrivateNetWorkingId, NetworkType = n.GetType().Name})) .OrderBy(n => n.Date); 

However, if the answer is: I need to send the Shutdown () command to the 10 oldest networks, then you really need a polymorphic solution , where you have one type that you can call Shutdown() , which will solve the specific Shutdown() method for the types, which you use.

A polymorphic solution to use only if the khellang answer user does n't work for you

From the comment to another answer

@BinaryWorrier I chose this answer because I already have entries in the databases, so if I want to add a new interface, how will I work with entries already saved before adding the interface?

I find it hard to believe that your ORM will not allow you to add an interface to an entity class, and not - somehow - mark this interface and / or its member so that they are ignored by ORM.

However, if you cannot add a new interface or base class, you can still do it polymorphically.

Add an interface, add a class that implements the interface for each of your network classes ( Abstractor classes), then convert the network classes to Abstractor classes by adding them to the List<INetwork> and sorting this list.

 public interface INetwork { DateTime? Date { get; } } public class PrivateNetworkAbstractor :INetwork { private PrivateNetwork network; public PrivateNetworkAbstractor(PrivateNetwork network) { this.network = network; } public DateTime? Date { get { return network.DateCreation; } } } public class NetworkingAbstractor : INetwork { private Networking networking; public NetworkingAbstractor(Networking networking) { this.networking = networking; } public DateTime? Date { get { return networking.NetWorkingDate; } } } ... public IEnumerable<INetwork> MergenSort(IEnumerable<Networking> generalNetWorks, IEnumerable<PrivateNetwork> privateNetWorks) { return generalNetWorks.Select(n => new NetworkingAbstractor(n)).Cast<INetwork>() .Union(privateNetWorks.Select(n => new PrivateNetworkAbstractor(n)).Cast<INetwork>()) .OrderBy(n=> n.Date); } 
+2
source

Create an interface that has a date and is implemented in both classes. After that, sorting is simple.

 public interface INetwork { DateTime? Date { get; } } public partial class Networking :EntityBase, INetwork { public DateTime? Date { get { return NetWorkingDate; } } } public partial class PrivateNetwork :EntityBase, INetwork { public DateTime? Date { get { return DateCreation; } } } var commonList = new List<INetwork>(); // Add instances of PrivateNetwork and Networking to the list var orderedByDate = commonList.OrderBy(n => n.Date); 
+1
source

The first solution uses an anonymous type

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Example1 { class Program { class Human { public string Name { get; set; } public string Hobby { get; set; } public DateTime DateOfBirth { get; set; } } class Animal { public string Name { get; set; } public string FavouriteFood { get; set; } public DateTime DateOfBirth { get; set; } } static void Main(string[] args) { var humans = new List<Human> { new Human { Name = "Kate", Hobby = "Fitness", DateOfBirth = DateTime.Now.AddYears(-27), }, new Human { Name = "John", Hobby = "Cars", DateOfBirth = DateTime.Now.AddYears(-32), }, }; var animals = new List<Animal> { new Animal { Name = "Fluffy", FavouriteFood = "Grain", DateOfBirth = DateTime.Now.AddYears(-2), }, new Animal { Name = "Bongo", FavouriteFood = "Beef", DateOfBirth = DateTime.Now.AddYears(-6), }, }; var customCollection = (from human in humans select new { Name = human.Name, Date = human.DateOfBirth, } ).Union(from animal in animals select new { Name = animal.Name, Date = animal.DateOfBirth, }).OrderBy(x => x.Date); foreach (dynamic customItem in customCollection) Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name)); Console.Read(); } } } 

or without an anonymous type (created by CustomClass):

 ... class CustomClass { public string Name { get; set; } public DateTime Date { get; set; } } ... var customCollection = (from human in humans select new CustomClass { Name = human.Name, Date = human.DateOfBirth, } ).Union(from animal in animals select new CustomClass { Name = animal.Name, Date = animal.DateOfBirth, }).OrderBy(x => x.Date); foreach (CustomClass customItem in customCollection) Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name)); ... 
0
source

I just added a base class and made it the parent of both list classes. and then a simple union. he did the trick

0
source

All Articles