I have a Dictionary<string, CachedImage> with which I'd like to group the items, count the number of items in the group and iterate through each group if the count is greater than 6500.
The CachedImage class contains Path And ExpiresUtc properties that I am interested in.
My Linq-fu is sadly lacking with complex queries so this is as far as I have got and I think I've already messed up. I'm assuming what I want is possible.
Any help would be appreciated, especially with a quick walkthrough.
Regex searchTerm = new Regex(#"(jpeg|png|bmp|gif)");
var groups= PersistantDictionary.Instance.ToList()
.GroupBy(x => searchTerm.Match(x.Value.Path))
.Select(y => new
{
Path = y.Key,
Expires = y.Select(z => z.Value.ExpiresUtc),
Count = y.Sum(z => z.Key.Count())
})
.AsEnumerable();
Try this:
var groups = PersistantDictionary.Instance.ToList()
.GroupBy(x => searchTerm.Match(x.Value.Path).Value)
.Where(g => g.Count() > 6500);
foreach (var group in groups)
{
Console.WriteLine("{0} images for extension {1}", group.Count(), group.Key);
foreach (KeyValuePair<string, CachedImage> pair in group)
{
//Do stuff with each CachedImage.
}
}
So to break this down:
PersistantDictionary.Instance.ToList()
Produces a list of KeyValuePair<string, CachedImage>.
.GroupBy(x => searchTerm.Match(x.Value.Path).Value)
Groups the list by the Regex match against the Path of the CachedImage. Note that I have used the Value property - the Match method returns a Match object, so it would be best to group by the actual text of the match. The outcome of this step will be an IEnumerable of <IGrouping<string, KeyValuePair<string, CachedImage>>>.
.Where(g => g.Count() > 6500);
This ensures that only those groups with > 6500 items will be retrieved.
Related
var paymentTypes = _context
.BursaryTransactions
.Select(c => c.PaymentType)
.ToList();
string[] obj = paymentTypes
.ToArray();
var a = obj[1];
The first line retrieves a list of Payment type which are in strings from BursaryTransactions Table
the second line converts the list to array.
The list from the first line however contains Similar Strings for example
Post Utme
School Fee
School Fee
Post Utme
Hnd Form
Hnd Form
I want to filter these list and retrive just one occurrance of an item that appears more than once. then converts the new list to array.
You can try GroupBy and choose groups with more than 1 item:
var result = _context
.BursaryTransactions
.GroupBy(c => c.PaymentType) // Group By PaymentType
.Where(group => group.Count() > 1) // groups with more than 1 item
.Select(group => group.First()) // we want just the 1st item of such group
.ToList(); // materialized as a List<T>
Edit: to remove duplicates we can take First item from each group:
var result = _context
.BursaryTransactions
.GroupBy(c => c.PaymentType)
.Select(group => group.First()) // First().PaymentType if you want PaymentType only
.ToList();
You can try this way
var result = _context.BursaryTransactions.GroupBy(c => c.PaymentType)
.Where(g => g.Count() > 1)
.Select(g => g.First())
.ToArray();
Could you help me? I cant remove the same item in a list.
List<string> text = new List<string>();
text.Add("A");
text.Add("B");
text.Add("C");
text.Add("D");
text.Add("D");
text.Add("A");
foreach(string i in text)
{
Console.WriteLine(i);
}
the result is A,B,C,D,D,A but I need to be B,C . How can i do?
Here is my solution,
var result = text.GroupBy(x => x).Where(y => y.Count() == 1).Select(z => z.Key);
Console.WriteLine(string.Join(", ", result));
Explanation:
GroupBy(x => x): This will group list based on characters i.e predicate.
.Where(y => y.Count() == 1): This will filter elements which are duplicates.
.Select(z => z.Key): Select will create new enumerable which contains Keys from Grouped elements
Something like
text.GroupBy(t => t).Where(tg => tg.Count()==1).Select(td => td.First());
This proberly wont compile, you need to fix that your self.
The idea is:
1. Group by item.
2. Take all groups with exactly 1 item
3. Select the Item
So far, I have this:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)));
Configuration folder will contain pairs of files:
abc.json
abc-input.json
def.json
def-input.json
GetReportName() method strips off the "-input" and title cases the filename, so you end up with a grouping of:
Abc
abc.json
abc-input.json
Def
def.json
def-input.json
I have a ReportItem class that has a constructor (Name, str1, str2). I want to extend the Linq to create the ReportItems in a single statement, so really something like:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
**.Select(x => new ReportItem(x.Key, x[0], x[1]));**
Obviously last line doesn't work because the grouping doesn't support array indexing like that. The item should be constructed as "Abc", "abc.json", "abc-input.json", etc.
If you know that each group of interest contains exactly two items, use First() to get the item at index 0, and Last() to get the item at index 1:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
.Where(g => g.Count() == 2) // Make sure we have exactly two items
.Select(x => new ReportItem(x.Key, x.First(), x.Last()));
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x))).Select(x => new ReportItem(x.Key, x.FirstOrDefault(), x.Skip(1).FirstOrDefault()));
But are you sure there will be exactly two items in each group? Maybe has it sence for ReportItem to accept IEnumerable, not just two strings?
I am trying to use Linq to return me all of the items in my object that have a specific property value duplicated, and the maximum value of another specific property for all of the duplicates.
My object has properties CourseInfoId which is how I want to check for duplicates and a property Priority which i want the maximum value (and lots of other properties).
I thought this would work, but it's giving me every item in the object.
var group = from a in r
group a by a.CourseInfoId into b
let maxPriority = b.Max(d => d.Priority)
where b.Skip(1).Any()
from c in b
where c.Priority == maxPriority
select c;
Where am I going wrong?
What you'll want to do is group by CourseInfoId, then filter on groups that have more than 1 item which will get you all of the duplicate items. Next, you'll have to flatten out the groups again and get the maximum property value from the results.
var maxPriority = items
.GroupBy(i => i.CourseInfoId)
.Where(g => g.Count() > 1)
.SelectMany(g => g)
.Max(i => i.Priority);
EDIT: I see now that you only want to check the properties of the duplicates, not all of the items with a duplicate ID. All you have to do is skip the first item of each group in the .SelectMany() call:
var maxPriority = items
.GroupBy(i => i.CourseInfoId)
.Where(g => g.Count() > 1)
.SelectMany(g => g.Skip(1))
.Max(i => i.Priority);
I want to access the first, second, third elements in a list. I can use built in .First() method for accessing first element.
My code is as follows:
Dictionary<int, Tuple<int, int>> pList = new Dictionary<int, Tuple<int, int>>();
var categoryGroups = pList.Values.GroupBy(t => t.Item1);
var highestCount = categoryGroups
.OrderByDescending(g => g.Count())
.Select(g => new { Category = g.Key, Count = g.Count() })
.First();
var 2ndHighestCount = categoryGroups
.OrderByDescending(g => g.Count())
.Select(g => new { Category = g.Key, Count = g.Count() })
.GetNth(1);
var 3rdHighestCount = categoryGroups
.OrderByDescending(g => g.Count())
.Select(g => new { Category = g.Key, Count = g.Count() })
.GetNth(2);
twObjClus.WriteLine("--------------------Cluster Label------------------");
twObjClus.WriteLine("\n");
twObjClus.WriteLine("Category:{0} Count:{1}",
highestCount.Category, highestCount.Count);
twObjClus.WriteLine("\n");
twObjClus.WriteLine("Category:{0} Count:{1}",
2ndHighestCount.Category, 2ndHighestCount.Count);
// Error here i.e. "Can't use 2ndHighestCount.Category here"
twObjClus.WriteLine("\n");
twObjClus.WriteLine("Category:{0} Count:{1}",
3rdHighestCount.Category, 3rdHighestCount.Count);
// Error here i.e. "Can't use 3rdHighestCount.Category here"
twObjClus.WriteLine("\n");
I have written extension method GetNth() as:
public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
{
if (n < 0)
throw new ArgumentOutOfRangeException("n");
if (n > 0){
int c = 0;
foreach (var e in list){
if (c % n == 0)
yield return e;
c++;
}
}
}
Can I write extension methods as .Second(), .Third() similar to
built in method .First() to access second and third indices?
If what you're looking for is a single object, you don't need to write it yourself, because a built-in method for that already exists.
foo.ElementAt(1)
will get you the second element, etc. It works similarly to First and returns a single object.
Your GetNth method seems to be returning every Nth element, instead of just the element at index N. I'm assuming that's not what you want since you said you wanted something similar to First.
Since #Eser gave up and doesn't want to post the correct way as an answer, here goes:
You should rather do the transforms once, collect the results into an array, and then get the three elements from that. The way you're doing it right now results in code duplication as well as grouping and ordering being done multiple times, which is inefficient.
var highestCounts = pList.Values
.GroupBy(t => t.Item1)
.OrderByDescending(g => g.Count())
.Select(g => new { Category = g.Key, Count = g.Count() })
.Take(3)
.ToArray();
// highestCounts[0] is the first count
// highestCounts[1] is the second
// highestCounts[2] is the third
// make sure to handle cases where there are less than 3 items!
As an FYI, if you some day need just the Nth value and not the top three, you can use .ElementAt to access values at an arbitrary index.