I'm trying to make an android synchronization between client and ASP.NET MVC server. The logic is simple, my next method receives a data dictionary, where key = idGroup and value = LastMessageIdKnown, in the end I should get the next messages for each group what Id is higher than the LastMessageIdKnown (the value of my dictionary).
Right now I am iterating the map, for each key I do a query to my SQL database but this is inefficient, if I got N keys you can imagine what implying.
This is my current method
public Dictionary<int, List<Messages>> SynchronizedChatMessages(Dictionary<int, int> data)
{
Dictionary<int, List<Messages>> result = new Dictionary<int, List<Messages>>();
foreach(int item in data.Keys){
var idMessage= data[item];
var listMessages= _context.Messages.Where(x => x.Grupo_ID == item && x.ID > idMessage).ToList();
result.Add(item,listMessages);
}
return result;
}
How can I improve this query to get all what I need in an only and optimal way?
Thank you.
Here's an attempt that uses Predicates to make it so that there is only one Where against the whole collection of messages.
Note that I mocked this up without a database, so I am passing a List into the SynchronizedChatMessages function, whereas you have the context available.
What remains to be proven is that this way of doing things only generates one query to the database (since I did it in objects only). The whole program is further, below, but first, just the function showing use of predicates to achieve firing the Where only once.
public static Dictionary<int, List<Message>> SynchronizedChatMessages(List<Message> messages, Dictionary<int, int> data)
{
List<Predicate<Message>> predList = new List<Predicate<Message>>();
//Built of list of indivIdual predicates
foreach (var x in data)
{
var IdMessage = x.Key;
var lastMessageId = x.Value;
Predicate<Message> pred = m => m.IdGroup.Id == IdMessage && m.Id > lastMessageId;
predList.Add(pred);
}
//compose the predicates
Predicate<Message> compositePredicate = m =>
{
bool ret = false;
foreach (var pred in predList)
{
//If any of the predicates is true, the composite predicate is true (OR)
if (pred.Invoke(m) == true) { ret = true; break; }
}
return ret;
};
//do the query
var messagesFound = messages.Where(m => compositePredicate.Invoke(m)).ToList();
//get the individual distinct IdGroupIds
var IdGroupIds = messagesFound.Select(x => x.IdGroup.Id).ToList().Distinct().ToList();
//Create dictionary to return
Dictionary<int, List<Message>> result = new Dictionary<int, List<Message>>();
foreach (int i in IdGroupIds)
{
result.Add(i, messagesFound.Where(m => m.IdGroup.Id == i).ToList());
}
return result;
}
Here is the whole thing:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication20
{
public class Program
{
public class Message
{
public int Id { get; set; }
public IdGroup IdGroup { get; set; }
}
public class IdGroup
{
public int Id { get; set; }
public List<Message> Messages { get; set; }
}
public static Dictionary<int, List<Message>> SynchronizedChatMessages(List<Message> messages, Dictionary<int, int> data)
{
List<Predicate<Message>> predList = new List<Predicate<Message>>();
//Built of list of indivIdual predicates
foreach (var x in data)
{
var IdMessage = x.Key;
var lastMessageId = x.Value;
Predicate<Message> pred = m => m.IdGroup.Id == IdMessage && m.Id > lastMessageId;
predList.Add(pred);
}
//compose the predicates
Predicate<Message> compositePredicate = m =>
{
bool ret = false;
foreach (var pred in predList)
{
//If any of the predicates is true, the composite predicate is true (OR)
if (pred.Invoke(m) == true) { ret = true; break; }
}
return ret;
};
//do the query
var messagesFound = messages.Where(m => compositePredicate.Invoke(m)).ToList();
//get the individual distinct IdGroupIds
var IdGroupIds = messagesFound.Select(x => x.IdGroup.Id).ToList().Distinct().ToList();
//Create dictionary to return
Dictionary<int, List<Message>> result = new Dictionary<int, List<Message>>();
foreach (int i in IdGroupIds)
{
result.Add(i, messagesFound.Where(m => m.IdGroup.Id == i).ToList());
}
return result;
}
public static void Main(string[] args)
{
var item1 = new IdGroup { Id = 2, Messages = new List<Message>() };
var item2 = new IdGroup { Id = 45, Messages = new List<Message>() };
var item3 = new IdGroup { Id = 36, Messages = new List<Message>() };
var item4 = new IdGroup { Id = 8, Messages = new List<Message>() };
var message1 = new Message { Id = 3, IdGroup = item1 };
var message2 = new Message { Id = 7, IdGroup = item1 };
var message3 = new Message { Id = 9, IdGroup = item1 };
item1.Messages.Add(message1);
item1.Messages.Add(message2);
item1.Messages.Add(message3);
var message4 = new Message { Id = 4, IdGroup = item2 };
var message5 = new Message { Id = 10, IdGroup = item2 };
var message6 = new Message { Id = 76, IdGroup = item2 };
item2.Messages.Add(message4);
item2.Messages.Add(message5);
item2.Messages.Add(message6);
var message7 = new Message { Id = 6, IdGroup = item3 };
var message8 = new Message { Id = 32, IdGroup = item3 };
item3.Messages.Add(message7);
item3.Messages.Add(message8);
var message9 = new Message { Id = 11, IdGroup = item4 };
var message10 = new Message { Id = 16, IdGroup = item4 };
var message11 = new Message { Id = 19, IdGroup = item4 };
var message12 = new Message { Id = 77, IdGroup = item4 };
item4.Messages.Add(message9);
item4.Messages.Add(message10);
item4.Messages.Add(message11);
item4.Messages.Add(message12);
List<IdGroup> items = new List<IdGroup> { item1, item2, item3, item4 };
List<Message> messages = new List<Message> { message1, message2, message3, message4, message5, message6,message7, message8, message9, message10, message11, message12};
Dictionary<int, int> lastMessagesPerItem = new Dictionary<int, int> { { 2, 3 }, { 45, 10 }, { 36, 6 }, { 8, 11 } };
var result = SynchronizedChatMessages(messages, lastMessagesPerItem);
var discard = Console.ReadKey();
}
}
}
Well it would be nice if this would work, but I doubt it that can be translated to a SQL statement in one go:
var toInsert =
from msg in _context.Messages
group msg by msg.Grupo_ID into g
where data.Keys.Contains(g.Key)
select new {
Item = g.Key,
Messages = g.Where(x => x.ID > data[g.Key])
};
I don't think the second Where clause x => x.ID > data[g.Key] can be translated.
So you may need to do this in two passes, like this:
// This is a single SQL query.
var groups =
from msg in _context.Messages
group msg by msg.Grupo_ID into g
where data.Keys.Contains(g.Key)
select new {
Item = g.Key,
// ordering helps us when we do the in-memory part.
Messages = g.OrderByDescending(x => x.ID).ToList()
};
// This iterates the result set in memory
foreach (var g in groups)
result.Add(
g.Item,
// input is ordered, we stop when an item is <= data[g.Item].
g.Messages.TakeWhile(m => m.ID > data[g.Item]).ToList())
Related
I would like to get the total order amount for each customer with Linq, I know I need to group and sum I have only succeeded to group without summing the whole amount for each order.
var OrderByCustumer = new[] {
new { name = "cust1", order = 400 },
new { name = "cust1", order = 250 },
new { name = "cust1", order = 130 },
new { name = "cust2", order = 30 },
new { name = "cust3", order = 205}
};
var res= OrderByCustumer.GroupBy(x=>x.name).Select((x,y)=>new{
a=x.Key
});
foreach(var a in res){
Console.WriteLine(a);
}
.**
OutPut
a = cust1
a = cust2
a = cust3
**
Try this
var res = OrderByCustumer.GroupBy(x => x.name).Select(x => new {
a = x.Key,
sum = x.Sum(c => c.order)
});
foreach (var item in res)
{
Console.WriteLine($"{ item.a} - Sum = {item.sum}");
}
IEnumerable<IGrouping<long, MyClass>> datas = list.GroupBy(x => x.PropertyXYOfMyClass);
// get all items from each group
foreach (var grouping in datas)
{
long groupKey = groupingByMyClass.Key;
//iterating through values
foreach (var item in groupingByMyClass)
{
long key = item.PropertyIntOfClassA;
string property = item.PropertyA;
}
}
Each group contains some items, wow to get values from first item of each group?
UPDATE
void Extract()
{
List<DataHolder> data = new List<DataHolder>();
List<DateTime> randomTimes = new List<DateTime>();
Random r = new Random();
DateTime d = new DateTime(2019, 9, 19, 7, 0, 0);
for (int i = 0; i < 100; i++)
{
DataHolder dh = new DataHolder();
TimeSpan t = TimeSpan.FromSeconds(r.Next(0, 14400));
dh.OID = i;
dh.Value = r.Next(50);
dh.Snapshottime = d.Add(t);
data.Add(dh);
}
data.OrderBy(o => o.Snapshottime).ToList();
List<DataHolder> SortedList = data.OrderBy(o => o.Snapshottime).ToList();
TimeSpan interval = new TimeSpan(0, 15, 0);
var result = SortedList.GroupBy(x => x.Snapshottime.Ticks / interval.Ticks) .OrderBy(x => x.Key);
}
public class DataHolder
{
public int OID { get; set; }
public double Value { get; set; }
public DateTime Snapshottime { get; set; }
}
Here from result i need to take first item from each group.
try this:
var finalResult = result.Select(gpr=>grp.First());
or if you want the earliest/Latest/etc you could order by first:
var finalResult = result.Select(gpr=>grp.OrderBy(x=>x.SnapShotTime).First());
You've already done the heavy lifting. Make a simple loop over the result:
var result = SortedList.GroupBy(x => x.Snapshottime.Ticks / interval.Ticks) .OrderBy(x => x.Key);
var resultList = new List<DataHolder>();
foreach(var group in result)
{
resultList.Add(group.First());
}
I hope this helps.
This question already has answers here:
Is there a good LINQ way to do a cartesian product?
(3 answers)
Closed 4 years ago.
I'm looking to get the Cartesian Product of an arbitrary number of objects in c#. My situation is slightly unusual - my inputs are not lists of base types, but objects which have a property that's a list of base types.
My input and output objects are as follows:
public class Input
{
public string Label;
public List<int> Ids;
}
public class Result
{
public string Label;
public int Id;
}
Some sample input data:
var inputs = new List<Input>
{
new Input { Label = "List1", Ids = new List<int>{ 1, 2 } },
new Input { Label = "List2", Ids = new List<int>{ 2, 3 } },
new Input { Label = "List3", Ids = new List<int>{ 4 } }
};
And my expected output object:
var expectedResult = new List<List<Result>>
{
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
}
};
If I knew the number of items in 'inputs' in advance I could do this:
var knownInputResult =
from id1 in inputs[0].Ids
from id2 in inputs[1].Ids
from id3 in inputs[2].Ids
select
new List<Result>
{
new Result { Id = id1, Label = inputs[0].Label },
new Result { Id = id2, Label = inputs[1].Label },
new Result { Id = id3, Label = inputs[2].Label },
};
I'm struggling to adapt this to an arbitrary number of inputs - is there a possible way to do this?
I consider this duplicate of question linked in comments, but since it was reopened and you struggle to adapt that question to your case, here is how.
First grab function by Eric Lippert from duplicate question as is (how it works is explained there):
public static class Extensions {
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item })
);
}
}
Then flatten your input. Basically just attach corresponding label to each id:
var flatten = inputs.Select(c => c.Ids.Select(r => new Result {Label = c.Label, Id = r}));
Then run cartesian product and done:
// your expected result
var result = flatten.CartesianProduct().Select(r => r.ToList()).ToList();
I'm not proud of the amount of time I spent messing with this, but it works.
It's basically black magic, and I would replace it the first chance you get.
public static List<List<Result>> Permutate(IEnumerable<Input> inputs)
{
List<List<Result>> results = new List<List<Result>>();
var size = inputs.Select(inp => factorial_WhileLoop(inp.Ids.Count)).Aggregate((item, carry) => item + carry) - 1;
for (int i = 0; i < size; i++) results.Add(new List<Result>());
foreach (var input in inputs)
{
for (int j = 0; j < input.Ids.Count; j++)
{
for (int i = 0; i < (size / input.Ids.Count); i++)
{
var x = new Result() { Label = input.Label, Id = input.Ids[j] };
results[(input.Ids.Count * i) + j].Add(x);
}
}
}
return results;
}
public static int factorial_WhileLoop(int number)
{
var result = 1;
while (number != 1)
{
result = result * number;
number = number - 1;
}
return result;
}
I am looking for the best algorithm to compare 2 collections and determine which element got added and which element got removed.
private string GetInvolvementLogging(ICollection<UserInvolvement> newInvolvement, ICollection<UserInvolvement> oldInvolvement)
{
//I defined the new and old dictionary's for you to know what useful data is inside UserInvolvement.
//Both are Dictionary<int, int>, because The Involvement is just a enum flag. Integer. UserId is also Integer.
var newDict = newInvolvement.ToDictionary(x => x.UserID, x => x.Involvement);
var oldDict = oldInvolvement.ToDictionary(x => x.UserID, x => x.Involvement);
//I Want to compare new to old -> and get 2 dictionaries: added and removed.
var usersAdded = new Dictionary<int, Involvement>();
var usersRemoved = new Dictionary<int, Involvement>();
//What is the best algoritm to accomplish this?
return GetInvolvementLogging(usersAdded, usersRemoved);
}
private string GetInvolvementLogging(Dictionary<int, Involvement> usersAdded, Dictionary<int, Involvement> usersRemoved)
{
//TODO: generate a string based on those dictionaries.
return "Change in userinvolvement: ";
}
Added elements are only in newDict removed only in oldDict
var intersection = newDict.Keys.Intersect(oldDict.Keys);
var added = newDict.Keys.Except(intersection);
var removed = oldDict.Keys.Except(intersection);
EDIT
I modify your base function, dictionaries is no neded.
Example UserInvolvement implementation
class UserInvolvement
{
public int UserId;
public string Name;
public string OtherInfo;
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
UserInvolvement p = obj as UserInvolvement;
if ((System.Object)p == null)
{
return false;
}
return (UserId == p.UserId) && (Name == p.Name) && (OtherInfo == p.OtherInfo);
}
public override string ToString()
{
return $"{UserId} - {Name} - {OtherInfo}";
}
}
And example function:
private static string GetInvolvementLogging(ICollection<UserInvolvement> newInvolvement,
ICollection<UserInvolvement> oldInvolvement)
{
var intersection = newInvolvement.Select(x => x.UserId).Intersect(oldInvolvement.Select(x => x.UserId));
var addedIds = newInvolvement.Select(x => x.UserId).Except(intersection);
var removedIds = oldInvolvement.Select(x => x.UserId).Except(intersection);
List<UserInvolvement> modifiedUI = new List<UserInvolvement>();
foreach (var i in intersection)
{
var ni = newInvolvement.First(a => a.UserId == i);
var oi = oldInvolvement.First(a => a.UserId == i);
if (!ni.Equals(oi))
{
modifiedUI.Add(ni);
}
}
List<UserInvolvement> addedUI = newInvolvement.Where(x => addedIds.Contains(x.UserId)).Select(w => w).ToList();
List<UserInvolvement> removedUI = oldInvolvement.Where(x => removedIds.Contains(x.UserId)).Select(w => w).ToList();
StringBuilder sb = new StringBuilder();
sb.AppendLine("Added");
foreach (var added in addedUI)
{
sb.AppendLine(added.ToString());
}
sb.AppendLine("Removed");
foreach (var removed in removedUI)
{
sb.AppendLine(removed.ToString());
}
sb.AppendLine("Modified");
foreach (var modified in modifiedUI)
{
sb.AppendLine(modified.ToString());
}
return sb.ToString();
}
And my test function:
static void Main(string[] args)
{
List<UserInvolvement> newUI = new List<UserInvolvement>()
{
new UserInvolvement()
{
UserId = 1,
Name = "AAA",
OtherInfo = "QQQ"
},
new UserInvolvement()
{
UserId = 2,
Name = "BBB",
OtherInfo = "123"
},
new UserInvolvement()
{
UserId = 4,
Name = "DDD",
OtherInfo = "123ert"
}
};
List<UserInvolvement> oldUI = new List<UserInvolvement>()
{
new UserInvolvement()
{
UserId = 2,
Name = "BBBC",
OtherInfo = "123"
},
new UserInvolvement()
{
UserId = 3,
Name = "CCC",
OtherInfo = "QQ44"
},
new UserInvolvement()
{
UserId = 4,
Name = "DDD",
OtherInfo = "123ert"
}
};
string resp = GetInvolvementLogging(newUI, oldUI);
WriteLine(resp);
ReadKey();
WriteLine("CU");
}
Result is:
Added
1 - AAA - QQQ
Removed
3 - CCC - QQ44
Modified
2 - BBB - 123
You could try with Linq:
var usersAdded = newDict.Except(oldDict);
var usersRemoved = oldDict.Except(newDict);
If you need dictionaries as a result you can cast:
var usersAdded = newDict.Except(oldDict).ToDictionary(x => x.Key, x => x.Value);
var usersRemoved = oldDict.Except(newDict).ToDictionary(x => x.Key, x => x.Value);
Think best algorithm will be
foreach (var newItem in newDict)
if (!oldDict.ContainsKey(newItem.Key) || oldDict[newItem.Key]!=newItem.Value)
usersAdded.Add(newItem.Key, newItem.Value);
foreach (var oldItem in oldDict)
if (!newDict.ContainsKey(oldItem.Key) || newDict[oldItem.Key]!=oldItem.Value)
usersRemoved.Add(oldItem.Key, oldItem.Value);
Finally this is my implementation of GetInvolvementLogging:
(the implementation of the string builder method is irrelevant for my question here)
private string GetInvolvementLogging(ICollection<UserInvolvement> newInvolvement, ICollection<UserInvolvement> oldInvolvement)
{
//I defined the new and old dictionary's to focus on the relevant data inside UserInvolvement.
var newDict = newInvolvement.ToDictionary(x => x.UserID, x => (Involvement)x.Involvement);
var oldDict = oldInvolvement.ToDictionary(x => x.UserID, x => (Involvement)x.Involvement);
var intersection = newDict.Keys.Intersect(oldDict.Keys); //These are the id's of the users that were and remain involved.
var usersAdded = newDict.Keys.Except(intersection);
var usersRemoved = oldDict.Keys.Except(intersection);
var addedInvolvement = newDict.Where(x => usersAdded.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value);
var removedInvolvement = oldDict.Where(x => usersRemoved.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value);
//Check if the already involved users have a changed involvement.
foreach(var userId in intersection)
{
var newInvolvementFlags = newDict[userId];
var oldInvolvementFlags = oldDict[userId];
if ((int)newInvolvementFlags != (int)oldInvolvementFlags)
{
var xor = newInvolvementFlags ^ oldInvolvementFlags;
var added = newInvolvementFlags & xor;
var removed = oldInvolvementFlags & xor;
if (added != 0)
{
addedInvolvement.Add(userId, added);
}
if (removed != 0)
{
removedInvolvement.Add(userId, removed);
}
}
}
return GetInvolvementLogging(addedInvolvement, removedInvolvement);
}
I have been trying to make for each loop with the index as the key
this case i want to made a logic if the input user is match with index and i will show foreach all of the data which has index as the key
I made two class like this
class DataContainer
{
public DataContainer()
{
}
public int index { get; set; }
public List<DataValue> DataValue { get; set; }
}
class DataValue
{
public DataValue()
{
IntegerValues = new List<int>();
}
public string name { get; set; }
public List<int> IntegerValues { get; set; }
}
after that i try to make list of datacontainer like this
List<DataContainer> harakatSininilMabsutoh = new List<DataContainer>(){
new DataContainer{index = 2015 , DataValue = new List<DataValue>()
{
new DataValue{name = "first",IntegerValues = {9,55,18,11}},
new DataValue{name = "second" ,IntegerValues = {5,54,18,11}},
new DataValue{name = "third" ,IntegerValues = {40,26,14,11}},
new DataValue{name = "four" ,IntegerValues = {22,0,5,10}},
new DataValue{name = "fifth" ,IntegerValues = {46,44,17,0}},
}
},
new DataContainer{index = 2013 , DataValue = new List<DataValue>()
{
new DataValue{name = "first",IntegerValues = {26,49,8,11}},
new DataValue{name = "second" ,IntegerValues = {19,42,8,11}},
new DataValue{name = "third" ,IntegerValues = {55,3,12,11}},
new DataValue{name = "fourth" ,IntegerValues = {27,4,23,8}},
new DataValue{name = "fifth" ,IntegerValues = {43,22,7,1}},
}
},
new DataContainer{index = 2001, DataValue = new List<DataValue>()
{
new DataValue{name = "first",IntegerValues = {35,44,27,10}},
new DataValue{name = "second" ,IntegerValues = {24,41,27,10}},
new DataValue{name = "third" ,IntegerValues = {36,30,26,10}},
new DataValue{name = "fourth" ,IntegerValues = {59,24,8,6}},
new DataValue{name = "fifth" ,IntegerValues = {29,27,26,1}},
}
}
};
and then i made a logic like this
int years = (this is user input);
if(years == 2015)
{
///How to for each this which has index 2015
}
else if (years = 2013)
{
//how to foreach this which has index 2013
}
else if (years = 2001)
{
//how to foreach this which has index 2001
The simplest is by using LINQ FirstOrDefault like this
int userinput = 2015;
DataContainer requested = harakatSininilMabsutoh.FirstOrDefault(x => x.index == userinput);
if (requested == null) //FirstOrDefault of a class will return null if not found
return;
foreach (DataValue val in requested.DataValue)
Console.WriteLine(val.name + ": " + string.Join(", ", val.IntegerValues));
Edit 2:
If you only need all the integers, without name, without anything else, then you could either do this to get the List<List<int>>:
int userinput = 2015;
List<List<int>> intValuesOnly = harakatSininilMabsutoh
.FirstOrDefault(x => x.index == userinput)
.DataValue
.Select(y => y.IntegerValues)
.ToList();
//Do whatever you want with intValuesOnly. This is everything that you have in a list of lists
or do this to get List<int> (flattened):
int userinput = 2015;
List<int> intValuesOnly = harakatSininilMabsutoh
.FirstOrDefault(x => x.index == userinput)
.DataValue
.SelectMany(y => y.IntegerValues)
.ToList();
//Do whatever you want with intValuesOnly. This is everything that you have in single list
As FirstOrDefault may return null if the userinput is not found, note that, if you are not using C#6, you may want to consider two steps LINQ:
int userinput = 2015;
DataContainer requested = harakatSininilMabsutoh.FirstOrDefault(x => x.index == userinput);
if (requested == null) //FirstOrDefault of a class will return null if not found
return;
List<List<int>> intValuesOnly = requested
.Select(y => y.IntegerValues)
.ToList();
//Do whatever you want with intValuesOnly. This is everything that you have in a list of lists
Firstly, note that in this line you have tried to use a type name as a property name:
public List<DataValue> DataValue { get; set; }
I've renamed this property to 'DataValues' as shown:
public List<DataValue> DataValues { get; set; }
You have a list ('harakatSininilMabsutoh'), each element of which is a DataContainer. Each DataContainer in the list has two properties: an index and a list of 'DataValues' (NB renamed from 'DataValue' in your post).
The looping logic you want will therefore be something like this:
var matchingYears = harakatSininilMabsutoh.Where(h => h.index == years);
foreach (var dataContainer in matchingYears)
{
foreach (var item in dataContainer.DataValues)
{
// Action required on each DataValue:
Debug.Print(item.name + " " + string.Join(",", item.IntegerValues));
}
}
You'll need to add the following 'using' statement to your class, since 'Where' is a LINQ extension method:
using System.Linq;
If you know that there will be exactly one matching year, you could add First() and remove the outer foreach loop. If you know there will be at most one matching year (but there could be zero), you can still remove the outer foreach loop but you should use FirstOrDefault() instead and test for null.