LINQ query code for complex merging of data - c#

I've posted this before, but I worded it poorly. I'm trying again with a more well thought out structure.
I have the following code and I am trying to figure out the shorter linq expression to do it 'inline'. Please examine the "Run()" method near the bottom. I am attempting to understand how to join two dictionaries together based on a matching identifier in one of the objects - so that I can use the query in this sort of syntax.
var selected = from a in items.List()
// etc. etc.
select a;
so that I can define my structure in code like ...
TModelViewModel = new TModelViewModel
{
TDictionary = from a in items... etc. etc...
}
instead of going through a bunch of foreach loops, extra object declarations, etc.
This is my class structure. The Run() method is what I am trying to simplify. I basically need to do this conversion inline in a couple of places, and I wanted to simplify it a great deal so that I can define it more 'cleanly'.
class TModel
{
public Guid Id { get; set; }
}
class TModels : List<TModel>
{
}
class TValue
{
}
class TStorage
{
public Dictionary<Guid, TValue> Items { get; set; }
}
class TArranged
{
public Dictionary<TModel, TValue> Items { get; set; }
}
static class Repository
{
static public TItem Single<TItem, TCollection>(Predicate<TItem> expression)
{
return default(TItem); // access logic.
}
}
class Sample
{
public void Run()
{
TStorage tStorage = new TStorage();
// access tStorage logic here.
Dictionary<TModel, TValue> d = new Dictionary<TModel, TValue>();
foreach (KeyValuePair<Guid, TValue> kv in tStorage.Items)
{
d.Add(Repository.Single<TModel, TModels>(m => m.Id == kv.Key),kv.Value);
}
}
}

Haven't really tested this, and it's quite ugly, but I think this should work:
Dictionary<TModel, TValue> d = new Dictionary<TModel, TValue>();
d = d.Concat(tStorage
.Items
.Select(i => new KeyValuePair<TModel, TValue>(
new TModel { Id = i.Key }, i.Value))).ToDictionary(i => i.Key, i => i.Value);

Related

Get contained type of list in generics, lambda

Even though I know that such libraries already exist, I have decided to create an MVC5 HtmlHelper library to generate Tables from a model. The point is to practice (actually learn) about generics and lambdas in C#.
I want my library to be able to generate an HTML table using a syntax such as:
#Html.DisplayTable(model => model.ListTest).Render()
At this point in time, the above code works perfectly. But when I attempted to add the method exclude it all went wrong ... And this is where I see how poor my understanding of lambdas and delegate is. (it is actually the first I wrote any code that took a delegate as a parameter)
Below is how I want my call to be made
#Html.DisplayTable(model => model.ListTest).Exclude(l => l.Col1).Render()
then here is the model that I provide to my view
public class TestViewModel
{
public List<RowViewModel> ListTest { get; set; }
}
where RowViewModel is defined as follow
public class RowViewModel
{
public string Col1 { get; set; } = "Col1Value";
public string Col2 { get; set; } = "Col2Value";
public string Col3 { get; set; } = "Col3Value";
}
My helper
public static class TableHelpers
{
public static HtmlTable<TValue> DisplayTable<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression) where TValue : IList
{
Func<TModel, TValue> deleg = expression.Compile();
var result = deleg(helper.ViewData.Model);
return new HtmlTable<TValue>(result);
}
}
And my "library logic"
public class HtmlTable<TValue> where TValue : IList
{
private TValue _inputModel;
private readonly TableViewModel _outputViewModel = new TableViewModel();
public HtmlTable(TValue model)
{
Init(model);
}
public HtmlTable<TValue> Init(TValue model)
{
if(model.Count == 0)
throw new ArgumentException("The list must not be empty");
_inputModel = model;
UpdateViewModel();
return this;
}
private void UpdateViewModel()
{
var subType = _inputModel.GetContainedType();
var properties = subType.GetProperties();
_outputViewModel.Header = properties.Select(p => p.Name).ToList();
_outputViewModel.Rows = new List<List<string>>();
foreach (var row in _inputModel)
{
var values = _outputViewModel.Header.Select(col => subType.GetProperty(col).GetValue(row, null).ToString()).ToList();
_outputViewModel.Rows.Add(values);
}
}
public HtmlTable<TValue> Exclude<TSubValue>(Expression<Func<TValue, TSubValue>> expression)
{
Func<TValue, TSubValue> deleg = expression.Compile();
var result = deleg(_inputModel);
return this;
}
}
I kind of have an idea of how it should be done if i was to specify the model of a row to my helper such as
#Html.DisplayTable<RowViewModel>(model => model.ListTest).Exclude(l => l.Col1).Render()
but I would really like to be able to determine the type contained in a list to make lambdas work.
All of this might not make any sense, but after struggling with understand lambdas from a theory point of view for a while i decided that it was better to stop reading articles and try to do something with it ...
I found the solution, and it was pretty simple.
All i had to do is replace the TValue in my Expression<Func<TModel, TValue>> expression with IEnumerable<TValue> and remove where TValue : IList.
This allows me to call
#Html.DisplayTable(model => model.ListTest)
without ever having to explicitly specify any of the generic types.

Generic C# LINQ Aggregrate without resorting to Dynamic ExpressionBuilder

How do I reuse LINQ aggregation queries on a set of generic C# types with a common shape or interface that is known at compile-time without resorting to black magic dynamic ExpressionBuilder stuff?
For example,
// Each "reportable" class has a decimal property to sum over:
interface IReportable<T> {
Expression<T, decimal> GetSummingExpr(); // no static interface methods :(
}
public static class ReportingExtensions {
public static IQueryable<decimal> Report<T>(this IQueryable<T> qry)
{
return x => x.Sum(qry.GetSummingExpr()); // unsure if interfaces can do this
}
}
var invoices = new Invoice [] { Invoice(100.0M), ... };
var quotes = new Quote [] { Quote(50.0M), ... };
// Ideal use-cases:
var invoiceReport = invoices.AsQueryable().Report();
var quoteReport = quotes.AsQueryable().Report();
// "Reportable" class implementations:
public class Invoice : IReportable<Invoice>
{
public decimal InvoiceTotal { get; set; }
public Expression<Func<Invoice, decimal>> GetTotalExpr()
{
return x => x.InvoiceTotal;
}
}
public class Quote : IReportable<Quote>
{
public decimal QuoteTotal { get; set; }
public Expression<Func<Quote, decimal>> GetTotalExpr()
{
return x => x.QuoteTotal;
}
}
I have tried various approaches, but I can't get it to work without introducing magic strings, ala x.GroupBy("InvoiceTotal").
To my limited knowledge, this stuff is hard because LINQ types are resolved before generics are "rendered" to "concrete types". However, all of the type signatures are known at compile-time, so it seems like something I should be able to coerce the compiler to do.

Trying to Utilise a generic <T> collection

I am using C# and I thought I finally had the chance to understand a Generic type. I have several strongly typed objects that need the same static method. Rather than create one static method for each type I thought I could make it generic. Something I have never done and really wanted too.
Here is where I invoke it.
bool isDuplicate = Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
Here is my static method which resides in a static class called Utilities.
public static bool GetDuplicates<T>(List<T> pBookings)
{
foreach (var item in pBookings)
{
var myVal = item.bookingId
}
return true;
}
So I want to get at the values within var item inside the foreach loop so I can do comparisons. It's definately passed pBookings because I can hover and they have a .Count() with a collection of my strongly typed object. I am missing something here, possibly a casting process. I was wondering if anyone could advise me where I am coming up short.
var myVal = item.bookingId - I cannot get the bookingID from item because I am lacking in some basic understanding here. bookingId doesn't exist, I just get access to extension methods such as .toString and .equals
ANSWER OF SORTS What I did based on all of your really helpful assistance. I utilised Anderson Pimentel. I'm probably still off the mark but wanted to garner anyones thoughts here.
So basically I have several booking models, all need checking for duplicates. I really wanted to understand Generics in this way. So what I did is. Created a base class.
public class BookingBaseModel
{
public int BookingID { get; set; }
public DateTime BookingStartDateTime { get; set; }
public DateTime BookingEndDateTime { get; set; }
}
Then had my booking classes all inherit whats common to all. Like this...
public class RoomBookingModel : BookingBaseModel
{
public string RoomName{ get; set; }
}
public class vehicleBookingModel : BookingBaseModel
{
public string vehicleName{ get; set; }
}
Then in my utilities static helper I did this..
public static void GetDuplicates<T>(List<T> items) where T : BookingBaseModel
{
foreach (var item in items)
{
int myId = item.ID;
DateTime startDateTime = item.BookingStartDateTime;
DateTime endDateTime = item.BookingEndDateTime;
//Do you logic here
}
}
Then finally did something like this in corresponding controller action.
RoomController...
Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
VehicleController....
Utilities.GetDuplicates<VehicleBookingModel>(vehicleBookings);
Is this basically how we go about using generics in this way?
The compiler has no hint of what type is T. If you have a base class (or an Interface) which has the bookingId attribute, like BaseModel, you can constrain the generic type like the following:
public class BaseModel
{
public int Id { get; set; }
}
public static bool GetDuplicates<T>(List<T> items) where T : BaseModel
{
foreach (var item in items)
{
var myId = item.Id;
//Do you logic here
}
return true;
}
Once you're inside your GetDuplicates method, you have lost all knowledge of the RoomBookingModel type. That's the point of generic methods - they should be able to act on whatever type has been passed in to them, e.g. the logic within them should be generic across any type.
So your foreach loop is fine - you know you've been given a list of something, and you know lists can be iterated. But inside that foreach, item is just a T. You don't know what actual type it is because any type could have been passed in. So it doesn't make sense to access a specific property or method off of item - for example, what if I called GetDuplicates passing in a List<int>? It wouldn't have a bookingId property.
As written by others, you don't know anything of T. A classical solution, used by LINQ (see for example GroupBy) is to have your method receive a delegate that does the key-extraction, like:
public static bool GetDuplicates<T, TKey>(List<T> pBookings, Func<T, TKey> selector)
{
foreach (var item in pBookings)
{
TKey key = selector(item);
}
return true;
}
You then use it like:
GetDuplicates(pBookings, p => p.bookingId);
If you like to use a generic method, you have to provide also a generic method, which is able to generate a key out of the specified type T. Luckily we have LINQ which already provides the needed parts to build your generic method:
internal class Extensions
{
public static IEnumerable<T> GetDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return source.GroupBy(keySelector)
.Where(group => group.Skip(1).Any())
.SelectMany(group => group);
}
public static bool ContainsDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return GetDuplicates(source, keySelector).Any();
}
}
By having this (and type inference) you can use these methods e.g. by calling:
var hasDuplicates = roomBookings.ContainsDuplicates(item => item.bookingId);
if(hasDuplicates)
{
Console.WriteLine("Duplicates found:");
foreach (var duplicate in roomBookings.GetDuplicates(item => item.bookingId))
{
Console.WriteLine(duplicate);
}
}
I wonder if generics is really the tool for the job here. Your needs would be better served if each of your strongly typed objects shared a common interface.
"I have several strongly typed objects that need the same static method."
In this situation, all of the classes must share a common feature, such as, for instance, a property BookingId.
So, you'd need to formalize this by extracting this common interface:
public interface IBooking
{
int BookingId{ get; }
}
Make sure that every one of your strongly typed items implements the interface:
public class RoomBooking : IBooking
{
//etc...
}
And now make your static method accept IBooking instances:
public static bool GetDuplicates(IEnumerable<IBooking> pBookings)
{
//does pBookings contain items with duplicate BookingId values?
return pBookings.GroupBy(b => b.BookingId).Any(g => g.Count() > 1);
}
An easy read that isn't obfuscated by the unnecessary use of generics.
Since there are no constraints or hints about what T is, the compiler does not have enough information. Consider
bool isDuplicate = Utilities.GetDuplicates<int>(roomBookings);
Clearly an int does not have a bookingId member.
Every possible specific type for T would have to have a common base class or interface that has a bookingId, and even then you would have to add a generic constraint to your method signature to access that.
Perhaps you are looking for something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Duplicates
{
public static class EnumerableExtensions
{
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter, IEqualityComparer<I> comparer )
{
var hashSet = new HashSet<I>(comparer);
foreach (var item in enumerable)
{
var identity = identityGetter(item);
if (hashSet.Contains(identity)) return true;
hashSet.Add(identity);
}
return false;
}
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter)
{
return enumerable.HasDuplicates(identityGetter, EqualityComparer<I>.Default);
}
}
public class Booking
{
public int BookingId { get; set; }
public string BookingName { get; set; }
}
public class Customer
{
public string CustomerId { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var bookings = new List<Booking>()
{
new Booking { BookingId = 1, BookingName = "Booking 1" },
new Booking { BookingId = 1, BookingName = "Booking 1" }
};
Console.WriteLine("Q: There are duplicate bookings?. A: {0}", bookings.HasDuplicates(x => x.BookingId));
var customers = new List<Customer>()
{
new Customer { CustomerId = "ALFKI", Name = "Alfred Kiss" },
new Customer { CustomerId = "ANATR", Name = "Ana Trorroja" }
};
Console.WriteLine("Q: There are duplicate customers?. A: {0} ", customers.HasDuplicates(x => x.CustomerId));
}
}
}

C# Multiple Keys to one Value

I am looking for a C# container that can map multiple keys to a single object. For example: a single person can be referenced by his English name, or his Spanish name. I want to do this so that I don't have to create multiple copies of Dictionaries, and when I add/remove from the structure, I only have to add/remove once. Does such a structure exist?
Yes it exists: Dictionary<TKey, TValue>
There is no reason why you can't add a single object instance with multiple keys:
public class Person
{
public string EnglishName { get; set; }
public string SpanishName { get; set; }
}
public static class PersonDictExtensions
{
public static void AddPerson(this IDictionary<string, Person> persons, Person person)
{
persons.Add(person.EnglishName, person);
persons.Add(person.SpanishName, person);
}
public static void RemovePerson(this IDictionary<string, Person> persons, Person person)
{
foreach (var item in persons.Where(x => object.ReferenceEquals(x.Value, person)).ToList())
{
persons.Remove(item.Key);
}
}
}
var person = new Person { EnglishName = "Foo", SpanishName = "Bar" };
var dict = new Dictionary<string, Person>();
dict.AddPerson(person);
dict.RemovePerson(person);
EDIT
Ups I understand: only one add and remove? Hm. Doesn't know that such a structure exists. Maybe you can add an extension method to handle that cases.
I changed the code...

Time-stamped, thread-safe data structure for time-based lookup?

I want to implement a list type data structure that can be appended to, with an associated time-stamp. The point of this is that I can then get all the data that is newer than a certain time-stamp.
I have tried doing this with a ConcurrantDicitionary but I'm not confident this is the best way to do it. I would much prefer to have a List< decimal[2] > for applications which I won't go into here. The first value of the array can have the timestamp and the second will be the value. Alternatively, could use List< TimeStampedObject >. However, apparently there is no such thing as a concurrent list in C#.
For the record, my data is ordered with regards to timestamp.
I want to be able to do things like:
public static Dictionary<DateTime, decimal> GetLatest(DateTime since, Dictionary<DateTime, decimal> requestedDict)
{
Dictionary<DateTime, decimal> returnList = new Dictionary<DateTime, decimal>();
returnList = requestedDict.Where(x => x.Key > since).ToDictionary(x => x.Key, x => x.Value);
return returnList;
}
UPDATE:
Here is the List item I have come up with; please let me know if this has any potential downfalls:
public class ConcurrentList: List<StampedValue>
{
ReaderWriterLockSlim _samplesLock = new ReaderWriterLockSlim();
public ConcurrentList() : base()
{
}
public void AddThreadSafe(StampedValue item){
this._samplesLock.EnterWriteLock();
try
{
this.Add(item);
}
finally
{
this._samplesLock.ExitWriteLock();
}
}
public List<StampedValue> GetLatest(long since){
return this.Where( s => s.Timestamp > since ).ToList();
}
public List<StampedValue> GetLatest(DateTime since){
throw new NotImplementedException();
}
}
public class StampedValue
{
public long Timestamp { get; set; }
public decimal Value { get; set; }
public StampedValue(long t, decimal v){
this.Timestamp = t;
this.Value = v;
}
}
Seems to me your best bet is just a List<T> that you protect with a ReaderWriterLockSlim. For example:
class Sample
{
public DateTime EventTime { get; set; }
public decimal Value { get; set; }
}
List<Sample> _samples = new List<Sample>();
ReaderWriterLockSlim _samplesLock = new ReaderWriterLockSlim();
// to get items after a particular date
List<Sample> GetSamplesAfterDate(DateTime dt)
{
_samplesLock.EnterReadLock();
try
{
return _samples.Where(s => s.EventTime >= dt).ToList();
}
finally
{
_samplesLock.ExitReadLock();
}
}
If your list is known to be in chronological order, then you can improve the performance by using binary search on the list to find the first item that's greater than or equal to your passed time stamp. I just used the LINQ version here because the point is to illustrate the locking.
Appending to the list is similar: acquire the write lock, append, and release the lock:
void AppendSample(Sample s)
{
_samplesLock.EnterWriteLock();
try
{
_samples.Add(s);
}
finally
{
_samplesLock.ExitWriteLock();
}
}
An alternative is to use List<KeyValuePair<DateTime, decimal>> rather than List<Sample>. The locking would remain the same.
This should perform quite well in most situations.
Have you looked at the SynchronizedCollection<T> class? It seems to me to be what you are looking for. You could also specialize SynchronizedKeyedCollection<K, T>
EDIT (2014/May/8):
The documentation I linked to above is not as clear or useful as one would like, as such it may be helpful to look at the reference implementation.

Categories

Resources