I had to switch my List<> to Dictionary<int,List> now I am struggling how to compare two values.
I need to compare Ids and i am getting an underline here
(m => m.Id == lastOpenedArticle.Id);
that 'KeyValuePair<int, Article>' does not contain a definition for 'Id' and no accessible extension method 'Id' accepting a first argument of type 'KeyValuePair<int, Article>'
The article contains the definition
var openedArticle = allOptimizationData.LastOpenedArticles.FirstOrDefault(m => m.Id == lastOpenedArticle.Id);
public static async void SaveLastOpenedArticle(ArticleDetailData lastOpenedArticle)
{
await Task.Run(() =>
{
Directory.CreateDirectory(Path.Combine(LangUpStorage.OptimalizationDataFolder));
var allOptimizationData = DeserializeAllOptimizationData();
var openedArticle = allOptimizationData.LastOpenedArticles.FirstOrDefault(m => m.Id == lastOpenedArticle.Id);
}
Is there a way to achieve comparison like i had when i used List with the dictionary?
Sorry I have never used Dictionary before plus i am a beginner
Working on the assumption that LastOpenArticles is the Dictionary<int,Article> that you mentioned:
var openedArticle = allOptimizationData.LastOpenedArticles
.FirstOrDefault(m => m.Value.Id == lastOpenedArticle.Id);
Keyvalue pairs have the Value and the Key properties.
so either m.Key or m.Value.Id depending on how you are using the ids
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.keyvaluepair-2?view=netcore-3.1
Related
I have a small problem, from the below code first we are finding hostelStops with ID, hostelName, InTime
then we are taking wardenkduty with DutyName, tasksStart
now, I want to check whether hostelStops-hostelName is exist in taskList-taskStart
var hostelStops =
(from item in Hostel.Where(tn => tn.HostelNumber == hostelNumber).SelectMany(x => x.Hostels)
select new
{
Id = item.Id,
hostelName = hostelName.Single(p => p.Id == item.hostelId).SymbolicName,
InTime = item.InTimeTime
}).ToList();
var taskList =
(from row in filteredWardenDuty
select new
{
dutyName = row.DutyName,
taskStart = row.WardenTasks.Select(x => x.Context.Start.PlaceId)
}).ToList();
so, i have written below code
var isExist =
from row in taskList
select new
{
task = row.taskStart.Contains((from item in hostelStops select item.hostelName ))
};
but, receiving error as
Error CS1929 'IEnumerable' does not contain a definition for 'Contains' and the best extension method overload 'MemoryExtensions.Contains<IEnumerable>(ReadOnlySpan<IEnumerable>, IEnumerable)' requires a receiver of type 'ReadOnlySpan<IEnumerable>'
You can't do someCollection.Contains(otherCollection), you have to do someCollection.Any(item => otherCollection.Contains(item)) (in english: "is any item from this collection contained in that collection") so something like:
row.taskStart.Any(ts => (from item in hostelStops select item.hostelName).Contains(ts));
It would perhaps be more performant to make your hostelstops into a hashset:
var hs = (from item in hostelStops select item.hostelName).ToHashSet();
...
row.taskStart.Any(ts => hs.Contains(ts));
You haven't been clear about what types these are; this will only work if the two collections are of the same basic type (like string) or a type that is able to be compared properly even if theyre different instances, for which you may have to write a custom comparer or an Equals/GetHashcode pair of overrides
I'm trying to generalize a duplicate checker function, which depending on which type of object, checks the properties said class has (provided in a configuration) are equal to those in another list.
I have decided to create a Dictionary, which will accept a type string for the key (Book, Author, Shop, etc.) and an array of properties that need to be equal.
Example of Dictionary enties:
"Book", ["Title", "CoverImage", "NumberOfPages"]
"Author", ["Name", "Address", "SomethingElse"]
Then, I pass an object to the function and use Reflection to get the name of the type...
obj.GetType().Name;
... which I then use to fetch the right KVP from the Dictionary, meaning that if I pass a Book object, I get "Book". We then use that to get the configuration via ...
configDictionary["obj.GetType().Name"]
... which gives us the array of strings that are the properties that we need to check equality on.
I've gotten to the part where I need something along the lines of
list.Where(x => --> for each of the strings in the array - x.GetType.GetProperty(string) && --> same for next string && same for next string
... and then I need to top it off with an...
x.Id != obj.Id
To make sure we check for duplicates based on our logic (different id's and matches on all properties but has different Id's thus - a duplicate).
The end query should look like
Books:
someList.Where(x =>
x.Title == obj.Title
&& x.CoverImage == obj.CoverImage
&& x.NumberOfPages == obj.NumberOfPages
&& x.Id != obj.Id)
.FirstOrDefault();
Authors:
someList.Where(x => x.Name == obj.Name
&& x.Address == obj.Address
&& x.SomethingElse == obj.SomethingElse
&& x.Id != obj.Id)FirstOrDefault();
Try to avoid reflection because it can slow down your application. As an alternative you can create a dictionary and put all comparators into it:
var configDictionary = new Dictionary<string, List<Func<object, object, bool>>>
{
{
"Book",
new List<Func<object, object, bool>>
{
(b1, b2) => ((Book)b1).Title == ((Book)b2).Title,
(b1, b2) => ((Book)b1).CoverImage == ((Book)b2).CoverImage,
(b1, b2) => ((Book)b1).NumberOfPages == ((Book)b2).NumberOfPages,
(b1, b2) => ((Book)b1).Id != ((Book)b2).Id,
}
},
// same for Authors
};
Now you can use it in Where method:
var typeName = obj.GetType().Name; // here we using Reflection but once per collection, not per each item
var first = someList.Where(x => configDictionary[typeName].All(f => f(x, obj))).FirstOrDefault();
Also, because FirstOrDefault also has overload that accept predicate last line can be rewritten to:
var first = someList.FirstOrDefault(x => configDictionary[typeName].All(f => f(x, obj)));
A better solution will be creating custom attribute which will tag property. Then in class override default method Equals which will get all properties with this attribute and return equality.
I am trying to link up the RestaurantId in the RestaurantReservationEventsTbl with the RestaurantID in the RestaurantTbl to display reservations that are only made for the currently logged in restaurant.
I am receiving the following error in my code operator == cannot be applied to operands of type int and iqueryable int
Here is what I am doing in my home controller
var RestaurantIDRestaurantTbl = from r in db.Restaurants select r.RestaurantID;
//var listOfRestaurantsReservations = db.RestaurantReservationEvents.ToList();
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => x.RestaurantID == RestaurantIDRestaurantTbl).ToList();
//return View(restaurants.Where(x => x.RestaurantEmailAddress == UserEmail).ToList());
//create partial view called _RestaurantReservation
return PartialView("_RestaurantReservations", listOfRestaurantsReservations);
You have to change your code to materialize the restaurantIds like this:
var RestaurantIDRestaurantTbl = (from r in db.Restaurants
select r.RestaurantID).ToList();
Then you may change the code as below for the comparison to work:
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => RestaurantIDRestaurantTbl.Contains(x.RestaurantID)).ToList();
Anyway this is not the best solution. I will write another example for you, just try this example if it is working or not and let me know for the result.
I would considering changing the code as below to be much more efficient:
var listOfRestaurantsReservations = (from r in db.Restaurants
join e in db.RestaurantReservationEvents
on r.RestaurantID equals e.RestaurantID
//where r.RestaurantID == something //if where condition needed
select e).ToList();
If your tables are not connected with foreignkeys please consider to read this documentation here to make a better structure of the tables since they are related to each-other.
If your tables are related as in documentation article you might have something like that:
var RestaurantIDRestaurantTbl = db.Restaurants.SingleOrDefault(x => x.RestaurantID == something);
if(RestaurantIDRestaurantTbl != null)
{
var listOfRestaurantsReservations = RestaurantIDRestaurantTbl.RestaurantReservationEvents.ToList();
}
{
// This will give you a list of IDs
var RestaurantIDRestaurantTbl = db.Restaurants
.Select(p => p.RestaurantID)
.ToList();
// Using .Any() is a better choice instead of .Contains()
// .Contains is used to check if a list contains an item while .Any will look for an item in a list with a specific ID
var listOfRestaurantsReservations = db.RestaurantReservationEvents
.Where(p => RestaurantIDRestaurantTbl.Any(r => r.pRestaurantID == p))
.ToList();
}
so I have the following situation:
I have a Dictionary like this:
Dictionary<Dictionary<string, string>, DateTime> expireDates = new Dictionary<Dictionary<string, string>, DateTime>();
where the inner dictionary'first string is filled by a value (lets call it articlenumber) and the second string is filled by a value named articleCode. Together, they are the Key to get the preferred DateTime I need.
I try to get the DateTime via Linq like this in a WCF-Service:
var cmps= dbComponents.Select(component => new WCFObjects.Contracts.Component()
{
ArticleNumber = component.ArticleNumber,
Sortiment = component.SortimentsCode,
... //irrelevant values
//PSEUDOCODE, NOT WORKING
ExpireDate = expireDates.Where(x => x.Value.Where(y => x.Key.Where(
z => z.Key == component.ArticleNumber
&& z.Value == component.SortimentsCode))).FirstOrDefault()
}).ToList();
But I am struggling to create the preferred linq-query to get the value where key == articlenumber and value == sortimentscode. I tried a few approaches, most of them giving me the error
Error 'System.DateTime' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.DateTime' could be found (are you missing a using directive or an assembly reference?)
but I can't figure it out and hope someone could help me out here.
Best regards,
getoveritde
Try
ExpireDate = expireDates.Where(
x => x.Key.Any(
y => y.Key == component.ArticleNumber && y.Value == component.SortimentsCode)
).Select(z => z.Value).FirstOrDefault()
I have this query code here :
//Get all records based on ActivityID and TaskID.
public IList<Model.questionhint> GetRecords1(int listTask, int listActivity)
{
IList<Model.questionhint> lstRecords = context.questionhints.ToList();
return lstRecords.GroupBy(x => new { x.QuestionNo, x.ActivityID, x.TaskID }).Where(a => a.TaskID == listTask && a.ActivityID == listActivity).ToList();
}
The error lies in the .Where statement, it says does not contain definition for ActivityID and TaskID.
Full error :
'System.Linq.IGrouping' does not contain a definition for 'ActivityID' and no extension method 'ActivityID' accepting a first argument of type 'System.Linq.IGrouping' could be found (are you missing a using directive or an assembly reference?)
I am weak in query statements, basically I want to retrieve records from database where activity id = something and task id = something and group them by questionNo, activityId and Task ID .
The simplest fix here is: filter (where) before you group; this will also reduce the work that the grouping has to do:
return context.questionhints
.Where(a => a.TaskID == listTask && a.ActivityID == listActivity)
.GroupBy(x => new { x.QuestionNo, x.ActivityID, x.TaskID })
.ToList();
The reason it isn't working in your original code is, as already mentioned, that GroupBy returns a sequence of groups - each of which has a .Key (your anonymous type) and is itself an IEnumerable<T> sequence of the items in that group.
However! Your method claims to return IList<Model.questionhint>; your grouped data is not, and will never be, an IList<Model.questionhint> - it will be an IList<IGrouping<{some anonymous type, Model.questionhint>>. So: you cannot group like that if you are claiming that it is an IList<Model.questionhint> - and since the grouping is an anonymous type, you can't change the return type to match. You have two choices:
don't group
group by something declarable (a custom type, or a Tuple<...>), and change the return type to match
For example:
public IList<IGrouping<Tuple<int,int,int>,Model.questionhint>>
GetRecords1(int listTask, int listActivity)
{
return context.questionhints
.Where(a => a.TaskID == listTask && a.ActivityID == listActivity)
.GroupBy(x => Tuple.Create(x.QuestionNo, x.ActivityID, x.TaskID))
.ToList();
}
change it to Where(a => a.Key.TaskID == listTask && a.Key.ActivityID == listActivity)
You are dealing with an IGrouping, of which the Key property is the anonymous object new { x.QuestionNo, x.ActivityID, x.TaskID }
This solves the original error, but now we are trying to return IGroupings, which is not the correct return type. A cleaner way of doing it would be
var groups = lstRecords.GroupBy(x => new { x.QuestionNo, x.ActivityID, x.TaskID }).Where(a => a.Key.TaskID == listTask && a.Key.ActivityID == listActivity);
IList<Model.questionhint> questionHints = new List<Model.questionhint>();
foreach(var group in groups)
{
questionHints.AddRange(group);
}
return questionHints;
Note, this code is untested. You can do all this in one linq line (as im sure Mark will), however i tend to split it for readability
Alternative
If your goal is to get all the questionHints that match the criteria, what is wrong with a simple Where clause?
lstRecords.Where(a=>a.TaskID == listTask && a.ActivityID == listActivity).ToList();
References
http://msdn.microsoft.com/en-us/library/bb344977.aspx