Linq GroupBy to alter list - linq

I have a list of items in an IList<>.Each listitem has a date and a few other fields.
I need to order the list by date and then change the list to only show a date for the first item and effectively set the date field to null for the other items if the date is repeated.
Example:
12/01/2012 500
12/01/2012 700
15/02/2012 900
15/02/2012 1100
27/05/2012 2000
Desired Result:
12/01/2012 500
null 700
15/02/2012 900
null 1100
27/05/2012 2000
Is this possible with the linq group by and order by?
Thanks

LINQ operators are not supposed to change the underlying data. You'd better use regular foreach if you're going to modify the data.
This should probably work:
var groups = items.GroupBy(x => x.Date).ToArray();
foreach (var group in groups)
{
foreach (var item in group.Skip(1)) item.Date = null;
}
I would avoid using such a construction since you'll have to double-check that GroupBy preserves order. Instead I would use something like this:
var sortedItems = items.OrderBy(x => x.Date);
var lastVisitedDate = (DateTime?) null;
foreach (var item in sortedItems)
if (Equals(item.Date, lastVisitedDate)) item.Date = null;
else lastVisitedDate = item.Date;

This should work:
var list = new List<DateItem>();
// Initialization ...
var dups = list.Select((Item,Index) => new{ Item,Index })
.GroupBy(x => x.Item.Date)
.Where(g => g.Count() > 1);
foreach(var dup in dups)
{
foreach (var nullable in dup.OrderBy(x => x.Item.Date).Skip(1))
{
list[nullable.Index].Date = null;
}
}
Assuming your class looks similar to this:
class DateItem {
public DateTime? Date;
public int OtherField;
}
Edit: Here's a working demo: http://ideone.com/cVL4G

One way is to use LINQ to get all of the followers and then set their dates to null in a loop:
// Use ToList() to make sortedItems non-lazy so it won't get ordered each time it's called.
var sortedItems = items.OrderBy(x => x.Date).ToList();
var followers = sortedItems.GroupBy(item => item.Date)
.SelectMany(group => group.Skip(1));
foreach (var follower in followers)
{
follower.Date = null;
}
// Now you can use sortedItems.
Or if you prefer the query syntax:
var followers = from item in sortedItems
group item by item.Date into grp
from follower in grp.Skip(1)
select follower;

Related

Unable to cast object of type 'System.Collections.Generic.HashSet`1[libraryWebProject.Major]' to type 'libraryWebProject.Major'

I have this code in the code behind file
LibraryArticlesEntities la = new LibraryArticlesEntities();
int id = 17;
if (Request.QueryString["TitleID"] != null)
{
id = Int32.Parse(Request.QueryString["TitleID"]);
}
var gettitle = la.Titles.Where(t => t.ID == id).Select(t => t.Title1);
header.InnerHtml += gettitle;
var sub = la.Titles.Where(t => t.ID == id).Select(t => t.Majors);
foreach (Major major in sub) // the error is here
{
subject.InnerHtml += major.MajorName + " ";
}
Here I'm using a LINQ query to fetch a list of majors but I get this error when I try to iterate over it and display their names:
Unable to cast object of type 'System.Collections.Generic.HashSet`1[libraryWebProject.Major]' to type 'libraryWebProject.Major'.
The relationship between Title and Major is many to many and I have an association table linking Title ID and Major ID
Please try to make sub a List<Major> by adding .ToList(); at the end of your select.
var sub = la.Titles.Where(t => t.ID > 0)
.SelectMany(a => a.Majors.Select(b=>b)).ToList();
This line:
var sub = la.Titles.Where(t => t.ID == id).Select(t => t.Majors);
and the fact that "The relationship between Title and Major is many to many"
implies that the result of the Select is a collection of collections, so your loop will have to be:
foreach (var listOfMajors in sub)
{
foreach (var major in listOfMajors)
{
// Do stuff
}
}
Old answer replaced after it was revealed that the question didn't actually include the code that was in error.
Please try with ToList() and use var in foreach:
var sub = la.Titles.Where(t => t.ID == id)
.Include(t => t.Majors)
.Select(t => t.Majors).ToList();//use tolist() here
foreach (var major in sub) // and add var here please
{
subject.InnerHtml += major.MajorName + " ";
}

Select from mulitle tables with count in Linq

I am busy with a small online voting web app, now I struggling to get the total number of votes for each party that I stored in a different table. Here is what I have tried, this method gets each party from the votes table named [dbo].[VoterCandidateMapping]
public List<int> GetAllPartIDs()
{
List<int> partieIDs = new List<int>();
var parties = (from votes in voteDB.VoterCandidateMappings
select votes.PartyID).Distinct().ToList();
partieIDs = parties;
return partieIDs;
}
Then I want to use this method to count each vote associated with a particular part, here is the code
public IQueryable<ResultsViewModel> GetResults()
{
int numberOfVotes = 0;
foreach (int IDs in GetAllPartIDs())
{
numberOfVotes = (from votes in voteDB.VoterCandidateMappings
where votes.PartyID == IDs ? true : false
select votes.VoterID).Count();
}
return (
from results in voteDB.VoterCandidateMappings
join parties in voteDB.Parties
on results.PartyID equals parties.Id
select new ResultsViewModel
{
PartyName = parties.Name,
TotalVotes = numberOfVotes
});
}
It runs and return almost every data but the total number of votes is the same
The reason why it does not work is that you are trying to store multiple values in a single numberOfVotes variable.
Let's go through code what you have now.
First foreach loop calculate votes for each party and assigns to numberOfVotes variable. Each time value is assigned, existing value in numberOfVotes is overwritten. In the end of loop numberOfVotes contains number of votes for the last party. This is value you are seeing in your results as you use the same variable to return results.
Here is one way to do it correctly:
public IQueryable<ResultsViewModel> GetResults()
{
var groupedVotes = voteDB.VoterCandidateMappings
.GroupBy(x => x.PartyID)
.Select(x => new { PartyId = x.Key, NumberOfVotes = x.Count());
return voteDB.Parties
.Select(x => new ResultsViewModel
{
PartyName = x.Name,
TotalVotes = groupedVotes
.Where(y => y.PartyId == x.Id)
.Select(y => y.NumberOfVotes)
.FirstOrDefault()
});
}

Trim whitespace from DataTable cells with Linq

This piece of code works to trim all spaces in each datacell of each datarow.
How can I get this code:
var dataRows = dataTable.AsEnumerable();
foreach (var row in dataRows)
{
var cellList = row.ItemArray.ToList();
row.ItemArray = cellList.Select(x => x.ToString().Trim()).ToArray();
}
into one line of code so I don't have to loop through each row? Something like this but it doesn't work:
dataTable.AsEnumerable().Select(y => y.ItemArray.ToList()).Select(x => x.ToString().Trim());
If you love LINQish stype:
dataTable.AsEnumerable().ToList()
.ForEach(row =>
{
var cellList = row.ItemArray.ToList();
row.ItemArray = cellList.Select(x => x.ToString().Trim()).ToArray();
});
With linq you can't change item values finally you should run for loop (or foreach) to change fields value.
for example
var iq = obj from dataTable.asEnumerable() select new{
PersonName = a.Field<string>("PersonName"),
PersonID = a.Field<decimal>("PersonID"),
ParticipantString = a.Field<string>("DisplayString"),
PersonUserName = d.Field<string>("UserName")
}

how to select collection type navigation property's value

I have 3 tables, team(id,name) player(id,teamid,name) playerdetail(id,playerid,height,weight), the relationship between team and player is one to many, the relationship between player and playerdetail is one to one.
I want to use eager loading to load all the information and print out the name of players who is higher than 2 meters.
I have write the code below,
using (var context = new TestEntities())
{
var query = from t in context.Teams.Include("Players.PlayerDetails") select t;
foreach (var v in query)
{
Console.WriteLine(v.Players.Any(x => x.PlayerDetails.Any(y => y.Height > 200)));
}
Console.Read();
}
It prints out only true and false, how can I modify it and make it print out the name of player?
Thanks in advance
Why don't you just query the players through context.Players like below?
using (var context = new TestEntities())
{
var query = context.Players.Include("Team").Include("PlayerDetails")
.Where(p => p.Height > 200);
foreach (var v in query)
{
Console.WriteLine(v.Name);
}
Console.Read();
}

Iterate data in anonymous variable

I have a DataTable containing some data, and I am going to fetch some data from it using Linq to datatable.
The query looks like this:
var requiredData=dt.AsEnumerable()
.Where(row => row.Field<byte>("id") == 1)
.Select(x=> {
id = x.Field<int>("id"),
YYYYY = x.Field<string>("ColumnName2"),
ZZZZZ = x.Field<string>("ColumnName3")
}
);
Now, Please how do I iterate-through "requiredData"?
You could use a foreach loop:
foreach (var item in requiredData)
{
// TODO: use item.id, item.YYYYY and item.ZZZZZ here
}

Resources