I find that I am repeating a lot of new object initialization code in Linq queries, for example when creating different overloaded methods that use the same query structure.
var result = ItemResponses
.GroupBy(ir => ir.ItemID)
.Select(
grouped => new
{
ItemID = grouped.Key,
Average = (double)grouped.Average(g => g.OptionValue),
...etc. lots of properties, similar structure across lots of methods...
...Would really love to be able to write this code once somewhere...
}
);
At first I thought using constructors might be one way of doing it, something along these lines:
var result = ItemResponses
.GroupBy(ir => ir.ItemID)
.Select(grouped => new TestClass(grouped) //or anonymous type
);
public class TestClass
{
public int ItemID { get; set; }
public double Average { get; set; }
public TestClass() {}
public TestClass(IGrouping<int, ItemRespons> values)
{
ItemID = values.Key;
Average = values.Average(g => g.OptionValue);
}
}
But I see that Linq (to Entities at least) only allows parameterless constructors and initializers. So this approach doesn't seem to work.
Is there another way I can achieve simplifying this type of repetive code, and only having it in one place?
Use a delegate:
Func<IQueryable<ItemResponse>,IEnumerable<TestClass>> SelectResult = q =>
q.GroupBy(ir => ir.ItemID)
.Select(
grouped => new TestClass
{
ItemID = grouped.Key,
Average = (double)grouped.Average(g => g.OptionValue),
...
});
Then you can use it like this:
var result = SelectResult(ctx.ItemResponse);
It's even better to make it a extension method of course:
public static class Extensions
{
public static IEnumerable<TestClass> SelectResult(this IQueryable<ItemResponse> q)
{
return q.GroupBy(ir => ...)
}
}
And use it like this:
var result = ctx.ItemResponses.SelectResult();
It's not possible for anonymous type projections because there is no way to define a typed result, except some non generic type like dynamic, object or IQueryable, but then you'll have problem consuming it.
However it is possible to reuse projections to a custom types (like your sample TestClass). But instead of constructor, you have to put the code in a expression returning method.
For instance, instead of this
public TestClass(IGrouping<int, ItemResponse> values)
{
ItemID = values.Key;
Average = values.Average(g => g.OptionValue);
// ...etc. lots of properties
}
you could use something like this
static Expression<Func<IGrouping<int, ItemResponse>, TestClass>> ToTestClass()
{
return values => new TestClass
{
ItemID = values.Key,
Average = values.Average(g => g.OptionValue)
// ...etc. lots of properties
};
}
and the sample query would be
var result = ItemResponses
.GroupBy(ir => ir.ItemID)
.Select(ToTestClass());
Related
Assuming I have an object class MyObject with the following properties:
class MyObject {
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
}
And I have an array of MyObject[] with the following elements:
MyObject[] myObjects => new MyObject[] { myObject1, myObject2, myObject3 };
How do I create a new instance myObject such that its MyProperty1, MyProperty2, and MyProperty3 are the sums of the respective properties for every such object in the array?
Currently, my implementation is as follows
MyObject MyObjectSummed => new MyObject()
{
MyProperty1 = myObjects.Sum(x => x.MyProperty1);
MyProperty2 = myObjects.Sum(x => x.MyProperty2);
MyProperty3 = myObjects.Sum(x => x.MyProperty3);
}
but I vaguely remember seeing a more efficient way of doing this using LINQ, using a single line of code.
Is this possible and can someone please point me in the right direction?
Thanks!
You need to update three properties, so having "one-liner" will make code very unreadable.
If asking about different LINQ approach instead of summarising three values, then Aggregate is your choice, check #Andy's answer.
If you wrap logic with the method then you can use any amount of lines inside the implementation, but keep it one-liner for the consumers.
Alternative approach can be an extension method for enumerable
public static MyObject CalculateSum(this IEnumerable<MyObject> objects)
{
var total = new MyObject();
foreach (var obj in objects)
{
total.MyProperty1 += obj.MyProperty1;
total.MyProperty2 += obj.MyProperty2;
total.MyProperty3 += obj.MyProperty3;
}
return total;
}
Usage is "one-liner" :)
var objects = new MyObject[] { myObject1, myObject2, myObject3 };
var sum = objects.CalculateSum();
Notice that all LINQ methods are extension methods, so you kinda using your own domain specific LINQ "one-liner" ;)
So if you do not want to mutate the original array, this is what you can do:
var result = myObjects.Aggregate(new MyObject(), (accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
If you do not care you can just do this:
By doing this way you are mutating the first element within the array.
var result = myObjects.Aggregate((accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
If performance is not an issue, you can use reflections. Then you can add and remove integer properties to your object without having to modify the code of adding. If you convert the return value of GetProperties() to a list, you can use the ForEach() method of List<T>, which even reduces your line count further.
MyObject myObjectSummed = new MyObject();
foreach(var prop in myObjectSummed.GetType().GetProperties().Where(p => p.PropertyType == typeof(int)))
{
prop.SetValue(myObjectSummed, myObjects.Sum(x => (int)prop.GetValue(x)));
}
But i recommend Fabio's answer: From my point of view, it's clearest way to write this logic. Having as few lines of code as possible is not always the best approach.
I am trying to write some code in Linq with lambda.This is my first code using lambda and i am facing an issue while updating Record.
My code is:
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
Table<NOTIF_RECIP> NOTIF_RECIP_alias = db.GetTable<NOTIF_RECIP>();
Table<NOTIF_SCHED> NOTIF_SCHED_alias = db.GetTable<NOTIF_SCHED>();
Table<mainframe_replication> mainframe_replication_alias = db.GetTable<mainframe_replication>();
var ids = NOTIF_SCHED_alias.Select(x => x.NOTIF_RPT_ID).ToArray();
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias,
mfr => mfr.RPT_ID,
nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= mfr.NOTIF_ID,
RecipAdd=nr.NOTIF_RECIP_ADDR
});
foreach(var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.NotifId = "Changedxyz";
//db.SubmitChanges();
}
}
}
I am getting Error in repljoinmf_data.NotifId = "Changedxyz";
Error says: Error 2 Property or indexer 'AnonymousType#3.NotifId' cannot be assigned to -- it is read only
Can someone please help me in this.I think it is because I am using var which is anonymous but how to solve the problem.Any help is appreciated.
Thanks
As the error suggests, anonymous class instances cannot be modified once they have been projected.
Although you could switch to a strong typed class, and then reassign the member properties, however, you have an opportunity to project the desired result in the preceding LINQ statement into the same anonymous class:
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias, mfr => mfr.RPT_ID, nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new // Anon Class projection
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= "Changedxyz", // *** No need to mutate this afterwards
RecipAdd=nr.NOTIF_RECIP_ADDR
});
Edit, Update isn't trivial assignment, suggested alternatives
Option #1 : Strongly typed Class with mutation after projection
Add a new class (I've guessed some types)
public class MyPoco
{
public int ReportId {get; set;}
public string Reportversion {get; set;}
public byte[] ReportBytes {get; set;}
public DateTime ReportDate {get; set;}
public int NotifId {get; set;}
public string RecipAdd {get; set;}
}
Which you can then project into (just specify the class name instead of anonymous):
(mfr, nr) => new MyPoco // Not anonymous
{
ReportId=mfr.RPT_ID,
...
And then do modification afterwards:
foreach(var repljoinmf_data in repljoinmf)
{
repljoinmf_data.NotifId = "SomeNewValue"
Option #2 - Create a method (or Func) which does the complex logic
Since you seem to have already materialized all the data, you are free to use complex functions in the property projections. Any of the available local variables (closure) are available to pass to thus function, as are the join lambda parameters (mfr, nr)
So for example, write a function to calculate your NotifId = "Changedxyz" replacement:
private string DoIntensiveLogic(mainframe_replication mfr, NOTIF_RECIP nr)
{
// Do Stuff
}
Which you can then use in your original anonymous projection:
(mfr, nr) => new // Anon Class projection
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= DoIntensiveLogic(mfr, nr), // Call the function each row
RecipAdd=nr.NOTIF_RECIP_ADDR
});
Anonymous types are immutable and hence created cannot be changed you have to create a new type.
To solve your issue you have to create your own type and avoid the use of anonymous type when a future update is needed.
your type may look like this
public class ReportInfo
{
public int Id{get; set;}
//the same thing for others properties
}
and your query will look like this
new ReportInfo() {
Id = mfr.RPT_ID,
Reportversion = mfr.RPT_VERS,
ReportBytes = mfr.RPT_BYTES.ToString(),
ReportDate = mfr.REPL_DTM.ToString(),
NotifId = mfr.NOTIF_ID,
RecipAdd = nr.NOTIF_RECIP_ADDR
})
than you can update easily your property
foreach(var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.NotifId = "Changedxyz";
//db.SubmitChanges();
}
More about anonymous Types
what the compiler is actually doing. When you write a line of code like this:
var o = new { property1 = expression1, ..., propertyN = expressionN };
the compiler infers the type of each expression, creates private fields of these inferred types, creates
public read-only properties for each of the fields, and creates a constructor that accepts all these
expressions. The constructor’s code initializes the private read-only fields from the expression results
passed in to it. In addition, the compiler overrides Object’s Equals, GetHashCode, and ToString
methods and generates code inside all these methods.
if you want to change 'NotifId' later, you can find a record by id and change the property.
Example:
var alias = mainframe_replication_alias.SingleOrDefault(mfr => mfr.NOTIF_ID == repljoinmf_data.NotifId);
if(alias != null)
alias.NOTIF_ID = "Changedxyz";
How would one implement LINQ to extract the Guid's from one collection of objects of type A such that they can exclude these Guids from another collection of objects of type B. Object A and Object B both have a Guid field called 'ID."
I have the following:
ObservableCollection<Component> component Component has a
field called ID of type Guid
ObservableCollection<ComponentInformation> ComponentInformationCollection ComponentInformation
has a field called ID of type Guid
My implementation:
component =>
{
if (component != null)
{
var cancelledComponents = new List<ComponentInformation>();
foreach (Component comp in component)
{
cancelledComponents.Add(new ComponentInformation() { ID = comp.ID });
}
this.ComponentInformationCollection.Remove(cancelledComponents);
}
});
I believe there is a more elegant solution which I've been working at to solve but the issue I keep running into is creating a 'new ComponentInformation' such that the types do not give me an error.
====== FINAL SOLUTION =======
var cancelledComponentIDs = new HashSet<Guid>(component.Select(x => x.ID));
this.ComponentInformationCollection.Remove(
this.ComponentInformationCollection.Where(x => cancelledComponentIDs.Contains(x.ID)).ToList());
Thank you to:
Jason - I used this as a template for my final solution (listed below).
Servy - While I could have used a comparer, I think for this particular scenario a comparer was not neccessary because of its one-time-use type of situation.
ComponentInformationCollection is a Silverlight DependencyProperty that will trigger a INotifyChangedEvent (MVVM pattern) when altered, so the solution above worked best for my situation.
I would do this:
var ids = new HashSet<Guid>(
component.Select(x => x.ID)
);
var keepers = ComponentInformationCollection.Where(x => !ids.Contains(x.ID));
If Component doesn't already define an Equals and GetHashCode that uses the ID to do the compare you can define a comparer such as this:
class ComponentComparer : IEqualityComparer<Component>
{
public int Compare(Component a, Component b)
{
return a.ID.CompareTo(b.ID);
}
public int GetHashCode(Component a)
{
return a.ID.GetHashCode();
}
}
Then you can just use:
var result = componentCollectionA.Except(componentCollectionB, new ComponentComparer());
(written off of the top of my head; may require minor modifications to get it to compile.)
LINQ will allow you to find the GUIDs you need, but LINQ sequences are generally immutable; you'll still need to use some kind of loop to actually change the collection. The trick is getting the correct instances of your original collection that you want to remove.
Implementing one of the equality/comparison interfaces is one way to go, and if you need to compare your objects for equality in multiple places, is definitely the way to go. If you don't want to do that, this should get you what you want:
var removeme = (from x in this.ComponentInformationCollection
join y in component on x.ID equals y.ID
select x).ToList();
removeme.ForEach(x => this.ComponentInformationCollection.Remove(x));
Thinking out loud (meaning I didn't create a project and types and compile this), but how about:
var cancelledComponents = component.Select(c=> new ComponentInformation() {ID = c.ID}).ToList();
cancelledComponents.ForEach(c => ComponentInformationCollection.Remove(c));
There are a number of ways to solve this... this is a pretty simple Linq statement to query the ones you are looking for from the collection.
var keep = typeAList.Where(a => typeBList.FirstOrDefault(b => a.ID == b.ID) == null);
Here is the little test app I put together to demo it.
class Program
{
static void Main(string[] args)
{
List<TypeA> typeAList = new List<TypeA>();
typeAList.Add(new TypeA() { ID = Guid.NewGuid() });
typeAList.Add(new TypeA() { ID = Guid.NewGuid() });
typeAList.Add(new TypeA() { ID = Guid.NewGuid() });
List<TypeB> typeBList = new List<TypeB>();
typeBList.Add(new TypeB() { ID = typeAList[0].ID });
typeBList.Add(new TypeB() { ID = typeAList[1].ID });
//this is the statement
var keep = typeAList.Where(a => typeBList.FirstOrDefault(b => a.ID == b.ID) == null);
}
}
class TypeA
{
public Guid ID { get; set; }
}
class TypeB
{
public Guid ID { get; set; }
}
This is my type:
public class myType
{
public int Id { get; set; }
public string name { get; set; }
}
And there is 2 collection of this type:
List<myType> FristList= //fill ;
List<myType> Excludelist= //fill;
And I need to exclude Excludelist from FristList something like the following:
List<myType> targetList =
FirstList.Where(m=>m.Id not in (Excludelist.Select(t=>t.Id));
What is your suggestion about the exact lambda expression of the above query?
Three options. One without any changes:
var excludeIds = new HashSet<int>(excludeList.Select(x => x.Id));
var targetList = firstList.Where(x => !excludeIds.Contains(x.Id)).ToList();
Alternatively, either override Equals and GetHashCode and use:
var targetList = firstList.Except(excludeList).ToList();
Or write an IEqualityComparer<MyType> which compares by IDs, and use:
var targetList = firstList.Except(excludeList, comparer).ToList();
The second and third options are definitely nicer IMO, particularly if you need to do this sort of work in various places.
I have an object that has 3 separate Dictionaries. The value parameter for each dictionary implements the same interface. What is the best method to combine the 3 dictionaries into one and perform a single query so the results from the query will be a single IEnumerable?
Here's a rough idea of I am trying to accomplish. My DataSet object contains 3 dictionaries, each of which should be very small (theoretically some could contain up to 100 elements, but except in the most extreme cases they will be always less than 20 and usually 6 or less).
The purpose of the GetAllId() method will be to retrieve the Id for several private fields in each element of each dictionary and return it as a single IEnumerable. The dictionary value objects all implement IIdQueryable, which defines a single method that will extract all of the required Id's in the object.
I have 2 different ideas on how to accomplish what I want, but I am not sure if there is a better way to accomplish this?
public class DataSet
{
Dictionary<Int32, Foo> dict1;
Dictionary<CustomKey, Bar> dict2;
Dictionary<Int32, Boo> dict3;
public IEnumerable<Int32> GetAllId
{
// need to retrieve Id from dict1, dict2, and dict3.
// implementation ideas below
}
}
Option 1
public IEnumerable<Int32> GetAllId
{
var q1 = dict.Values.SelectMany(g => g.GetId());
var q2 = dict.Values.SelectMany(g => g.GetId());
var q3 = dict.Values.SelectMany(g => g.GetId());
return q1.Concat(q2).Concat(q3);
}
Option 2
public IEnumerable<Int32> GetAllId
{
var c1 = dict1.Values.Cast<IIdQueryable>();
var c2 = dict2.Values.Cast<IIdQueryable>();
var c3 = dict2.Values.Cast<IIdQueryable>();
var collection = c1.Concat(c2).Concat(c3);
return collection.SelectMany(g => g.GetId());
}
Method #3
Since each object implements the same interface, is it possible to perform a single LINQ query on all 3 objects without casting?
I personally like Method #1 better as it doesn't involve casting anything, but I think Method #2 seems to be more readable.
If it is needed, here's a rough idea of how the interface is implemented
public interface IIdQueryable
{
IEnumerable<Int32> GetId();
}
public class Foo : IIdQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
public class Bar : IGuidQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
public class Boo : IGuidQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
EDIT:
The question title is the source of what I was hoping could be done (that is do all 3 lookups in a single query without casting). I clarified that above.
You just need one SelectMany call in the first approach:
public IEnumerable<Int32> GetAllId()
{
return dict1.Values
.Select(x => x.GetId())
.Concat(dict2.Values.Select( x=> x.GetId()))
.Concat(dict3.Values.Select(x => x.GetId()))
.SelectMany(x => x);
}
Personally I wouldn't duct-tape this together though, there is no performance impact by keeping the queries separate and just returning the concatenation like you did already in the first example - it is more readable to me:
public IEnumerable<Int32> GetAllId()
{
var q1 = dict1.Values.Select(g => g.GetId());
var q2 = dict2.Values.Select(g => g.GetId());
var q3 = dict3.Values.Select(g => g.GetId());
return q1.Concat(q2)
.Concat(q3)
.SelectMany(x => x);
}
Now this looks pretty close to the second approach already - but no cast needed.