Distinct Value from Linq Query - c#

I have the below class and linq query I am using to populate a grid!
The Title is the same for every row returned. What I am trying to do is populate mString with the distinct Title from the query so I can bind it to a seperate textblock.
I probably didnt need to show all the code, but maybe it will help. How can I show the distinct Title.
public class Items
{
public int Id { get; set; }
public string Details { get; set; }
public string Title { get; set; }
public int NewNumber { get; set; }
}
private ObservableCollection<Items> mItem = new ObservableCollection<Items>();
private string mString = string.Empty;
public string SpecTitle
{
get { return mString; }
}
public ObservableCollection<Items> GetItems
{
get { return mItem; }
}
Here is the linq query
var results = (from z in mContext.View
orderby z.ItemNumber ascending
where z.ItemId == mId
select new Items()
{
Id = z.ItemId,
Details = z.Details,
Title = z.ItemTitle,
NewNumber = z.ItemNumber
});
List<Items> mNewItems = results.ToList();
mItem.Clear();
mNewItems.ForEach(y => mItem.Add(y));

var titleList = mNewItems.Select(i => i.Title).Distinct().ToList();

Converting my comment into an answer:
just do Items.Select(x => x.Title).Distinct();.

There is an additional library called moreLinq https://code.google.com/p/morelinq/ that has an extenction distinctby that you can you to distinct based on the given key.
it would as simle as this
var results = (from z in mContext.View
orderby z.ItemNumber ascending
where z.ItemId == mId
select new Items()
{
Id = z.ItemId,
Details = z.Details,
Title = z.ItemTitle,
NewNumber = z.ItemNumber
}).DistinctBy(c=>c.Title).ToList();

You can implement your custom comparer for distinct:
public class ItemsComparer : IEqualityComparer<Items>
{
public bool Equals(Items x, Items y)
{
return x.Title == y.Title;
}
public int GetHashCode(Items obj)
{
return obj.Title.GetHashCode();
}
}
then just use
var titleList = mNewItems.Distinct(new ItemsComparer()).Select(t=>t.Items);

Related

Get properties in LINQ inside group by clause

I'm new to LINQ and I'm trying to group a list by two columns and use the count aggregate function but I'm not sure how to write this query properly.
Here is my class
public class Result
{
public string? Type { get; set; }
public int Age { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public int Count { get; set; }
}
First I read some data from a dataTable and add it to a list of Result without Count property
List<Result> list = new();
foreach (DataRow row in dataTable.Rows)
{
list.Add(new Result
{
Type =row["Type"].ToString(),
Age = int.Parse(row["Age"].ToString()),
Name = row["Name"].ToString(),
Description = row["Description"].ToString(),
});
}
Now I want to group by Age and Type, I wrote this query and it returns the right result but I'm wondering if there is another cleaner way to write this instead of using Select().FirstOrDefault() ?
IEnumerable<Result> myResult = list.GroupBy(x => new { x.Age, x.Type }).Select(gr =>
new Result
{
Age = gr.Key.Age,
Type = gr.Key.Type,
Name = gr.Select(x => x.Name).FirstOrDefault(),
Description = gr.Select(x => x.Description).FirstOrDefault(),
Count = gr.Count()
}).ToList();
You can try to use FirstOrDefault()?. to make it simple which use Null-conditional
IEnumerable<Result> myResult = list.GroupBy(x => new { x.Age, x.Type }).Select(gr =>
new Result
{
Age = gr.Key.Age,
Type = gr.Key.Type,
Name = gr.FirstOrDefault()?.Name,
Description = gr.FirstOrDefault()?.Description,
Count = gr.Count()
}).ToList();

Sorting and Updating a Generic List of Object based on a Sub Object

I have the following objects:
public class TestResult
{
public string SectionName { get; set; }
public int Score { get; set; }
public int MaxSectionScore { get; set; }
public bool IsPartialScore { get; set; }
public string Name { get; set; }
public int NumberOfAttempts { get; set; }
}
public class TestResultGroup
{
public TestResultGroup()
{
Results = new List<TestResult>();
Sections = new List<string>();
}
public List<TestResult> Results { get; set; }
public List<string> Sections { get; set; }
public string Name { get; set; }
public int Rank { get; set; }
}
So, a TestResultGroup can have any number of results of type TestResult. These test results only differ by their SectionName.
I have a List<TestResultGroup> which I need to sort into descending order based on a score in the Results property, but only when Results has an item whos SectionName = "MeanScore" (if it doesnt have this section we can assume a score of -1). How would I go about ordering the list? Ideally I would also like to apply the result of this ordering to the Rank property.
Many Thanks
List<TestResultGroup> groups = ...
// group test result groups by the same score and sort
var sameScoreGroups = groups.GroupBy(
gr =>
{
var meanResult = gr.Results.FirstOrDefault(res => res.SectionName == "MeanScore");
return meanResult != null ? meanResult.Score : -1;
})
.OrderByDescending(gr => gr.Key);
int rank = 1;
foreach (var sameScoreGroup in sameScoreGroups)
{
foreach (var group in sameScoreGroup)
{
group.Rank = rank;
}
rank++;
}
// to obtain sorted groups:
var sortedGroups = groups.OrderByDescending(gr => gr.Rank).ToArray();
Or even write one expression with a side effect:
List<TestResultGroup> groups = ...
int rank = 1;
var sortedGroups = groups
.GroupBy(
gr =>
{
var meanResult = gr.Results.FirstOrDefault(res => res.SectionName == "MeanScore");
return meanResult != null ? meanResult.Score : -1;
})
.OrderByDescending(grouping => grouping.Key)
.SelectMany(grouping =>
{
int groupRank = rank++;
foreach (var group in grouping)
{
group.Rank = groupRank;
}
return grouping;
})
.ToArray(); // or ToList

Can't get items from DDS via query LINQ

I am new to C# ASP.NET and I am trying to get the items from a store (EPiServer).
Visual Studio says
Cannot resolve symbol Where, OnderzoekId and ToList
What am I doing wrong? I used this code example:
[EPiServerDataStore(AutomaticallyCreateStore = true, AutomaticallyRemapStore = true)]
public class OnderzoekColumn
{
private static int Counter = 0;
public Identity Id { get; set; }
public int ColumnId { get; set; }
public int OnderzoekId { get; set; }
public string ColumnName { get; set; }
public OnderzoekColumn()
{
Initialize();
}
public OnderzoekColumn(int onderzoekId, string columnName)
{
Initialize();
OnderzoekId = onderzoekId;
ColumnName = columnName;
}
protected void Initialize()
{
Id = Identity.NewIdentity(Guid.NewGuid());
ColumnId = System.Threading.Interlocked.Increment(ref Counter);
OnderzoekId = 0;
ColumnName = string.Empty;
}
public static List<OnderzoekColumn> GetOnderzoekColumns(int onderzoekId)
{
var store = typeof(OnderzoekColumn).GetStore();
var columns = from c in store
where c.OnderzoekId == onderzoekId
select c;
if (columns == null)
{
return new List<OnderzoekColumn>();
}
return columns.ToList<OnderzoekColumn>();
}
}
The linq statement
var columns = from c in store
where c.OnderzoekId == onderzoekId
select c;
is trying to enumerate over a collection, but the GetStore() method returns a single item. Try using the following code in place of your GetOnderzoekColumns method (its untested)
public static List<OnderzoekColumn> GetOnderzoekColumns(int onderzoekId)
{
var store = typeof(OnderzoekColumn).GetStore();
var columns = store.Items<OnderzoekColumn>().Where(c => c.OnderzoekId == onderzoekId);
return columns.ToList();
}
I'd add the following extension methods to your solution, then you can use a strongly typed Find method, which will be more efficient than the above, which returns all items, then filters in memory using the linq Where() method.
I used the following code to get it to work. I removed the AutomaticallyCreateStore and AutomaticallyRemapStore attribute also.
public static List<OnderzoekColumn> GetOnderzoekColumns(int onderzoekId)
{
var store = DynamicDataStoreFactory.Instance.GetStore(typeof(OnderzoekColumn));
var query = from item in store.Items<OnderzoekColumn>()
where item.OnderzoekId == onderzoekId
select item;
return query.ToList();
}

Linq to objects filtering IN and not in

Looking for an example where I can filter my collection based on some filtering criteria.
I have been looking for some example where given a list /array i can filter a collection.
In the example below in my find method I am trying to filter based on 2 values ,looking for something like an "IN" function any suggestions?
class Program
{
static void Main()
{
//Print all customres that belong to below deparments and match on surname
var criteria=new Criteria
{
Departments = new List<string> {"BusinessAnalyst", "Account"},
Surname = "Bloggs"
};
List<Customer> customers = Repository.Find(criteria);
customers.ForEach(x => Console.WriteLine(string.Format("Surname: {0} Department :{1}", x.Surname,x.Department)));
Console.Read();
}
}
public class Repository
{
public static List<Customer>GetCustomers()
{
return new List<Customer>
{
new Customer { Name = "Jon",Surname="Smith",Department = DepartmentType.Managers},
new Customer{Name = "Bill",Surname = "Gates",Department = DepartmentType.Managers},
new Customer { Name = "Mary",Surname = "Bug",Department = DepartmentType.Developers},
new Customer { Name = "Mark",Surname="Boo",Department = DepartmentType.Account},
new Customer{Name = "Ron",Surname = "Scott",Department = DepartmentType.Managers},
new Customer { Name = "Jonny",Surname = "Dip",Department = DepartmentType.Developers},
new Customer { Name = "Mary",Surname = "Bloggs",Department = DepartmentType.BusinessAnalyst},
new Customer { Name = "Mary",Surname = "Bug",Department = DepartmentType.Account},
new Customer { Name = "Jonny",Surname = "Dip",Department = DepartmentType.Account},
new Customer { Name = "Mary",Surname = "Bloggs",Department = DepartmentType.Managers}
};
}
public static List<Customer> Find(Criteria criteria)
{
List<Customer>customers=Repository.GetCustomers();
//Filter on departments
//ERROR HERE AS I cannot do this "IN" would be fantastic.
customers = customers.Contains(criteria.Departments);
//now filter on name
customers = customers.Where(x => x.Surname == criteria.Surname).ToList();
return customers;
}
}
public enum DepartmentType
{
Account,
Managers,
Developers,
BusinessAnalyst
}
public class Customer
{
public string Name { get; set; }
public string Surname { get; set; }
public DepartmentType Department { get; set; }
}
public class Criteria
{
public Criteria()
{
Departments=new List<string>();
}
public string Name { get; set; }
public string Surname { get; set; }
public List<string> Departments { get; set; }
}
public static List<Customer> Find(Criteria criteria)
{
List<Customer> customers = Repository.GetCustomers();
var customers2 = customers.Where(x => criteria.Departments.Contains(x.Department.ToString()));
var customers3 = customers2.Where(x => x.Surname == criteria.Surname);
return customers3.ToList();
}
But considering you use an enum for the Department (DepartmentType), shouldn't your Criteria class use the same instead of a string?
If you define the criteria.Departments as List<DepartmentType> then you can write
public static List<Customer> Find(Criteria criteria)
{
List<Customer> customers = Repository.GetCustomers();
var customers2 = customers.Where(x => criteria.Departments.Contains(x.Department));
var customers3 = customers2.Where(x => x.Surname == criteria.Surname);
return customers3.ToList();
}
Contains returns a bool defining whether a specified object is contained in a collection. Based on your example, you will need to use Where to filter the customers, then use Contains on the departments:
customers = customers.Where(c => criteria.Departments.Contains(c.Department));
i think you want something like this..
customers = customers.Where(c => criteria.Departments.Contains(c.Department));
You want
Customers.Where(c => criteria.Departments.Contains(c.Department.ToString()))
Not sure if this is what you're looking for but the following:
List<Customer> FilteredCustomers = (from c in customers where Criteria.Departments.Contains(c.deparment) && c.surname == Criteria.Surname select c).ToList();
Would equate to something like this in SQL:
SELECT *
FROM Customers
WHERE Department IN (
List of departments
)
AND Surname = surname
I haven't tested this but I think it should work and bring back what you want.

Distinct with custom comparer

Trying to use Distinct() using a custom comparer and it gives me the error:
cannot be inferred from the usage. Try specifying the type arguments explicitly
The Default comparer works fine but doesn't give the results I expect of course. How can I fix this?
public class TimeEntryValidation
{
public string EmployeeID { get; set; }
public string EmployeeLocation { get; set; }
public string EmployeeDepartment { get; set; }
public int RowIndex { get; set; }
}
public class MyRowComparer : IEqualityComparer<TimeEntryValidation>
{
public bool Equals(TimeEntryValidation x, TimeEntryValidation y)
{
return (x.EmployeeDepartment == y.EmployeeDepartment && x.EmployeeLocation == y.EmployeeLocation);
}
public int GetHashCode(TimeEntryValidation obj)
{
return obj.EmployeeID.GetHashCode();
}
}
void Query(List<TimeEntryValidation> listToQuery)
{
var groupedData =
from oneValid in listToQuery
group oneValid by oneValid.EmployeeID
into g
where g.Count() > 1
select new {DoubleItems = g};
var listItems = groupedData.Distinct(new MyRowComparer());
}
The type of groupedData is some IEnumerable<{an anonymous type}> whereas MyRowComparer is IEqualityComparer<TimeEntryValidation>
It's unclear whether you intended listItems to be a list of groups, or whether you wanted the actual items themselves.
If it's the latter, you probably want something like this:
void Query(List<TimeEntryValidation> listToQuery)
{
var groupedData = from oneValid in listToQuery
group oneValid by oneValid.EmployeeID
into g
where g.Count() > 1
select g ;
var listItems = groupedData.SelectMany(group => group).Distinct(new MyRowComparer());
//listItems is now an IEnumerable<TimeEntryValidation>
}

Categories

Resources