int itemCount=3;
prod.Add("P1");
prod.Add("P2");
prod.Add("P1");
prod.Add("P2");
prod.Add("P1");
prod.Add("P3");
In this prod list I want to get count of each item and if the count matches the itemCount then need to put it in an array.
In this case only P1 must be put to array.
Can anyone help me out? I want code in C#.
If prod is a IEnumerable<string>, you can do this with linq
var results =
(from s in prod
group s by s into g
where g.Count() == itemCount
select g.Key)
.ToArray();
I assumed that prod is List<string> or IEnumerable<string> in general:
var items = prod.GroupBy(x => x)
.Where(g => g.Count() == itemCount)
.Select(g => g.Key)
.ToArray();
Related
A sequence of non-empty strings stringList is given, containing only uppercase letters of the Latin alphabet. For all strings starting with the same letter, determine their total length and obtain a sequence of strings of the form "S-C", where S is the total length of all strings from stringList that begin with the character C. Order the resulting sequence in descending order of the numerical values of the sums, and for equal values of the sums, in ascending order of the C character codes.
This question is related to one of my previous questions.
One solution that works is this one:
stringList.GroupBy(x => x[0]).Select(g => $"{g.Sum(x => x.Length)}-{g.Key}");
The problem is that with this given example I don't know where to add the OrderByDescending()/ThenBy() clauses in order to get the correctly sorted list.
Create an intermediate data structure to store needed info and use it for sorting and then building the output:
stringList
.GroupBy(x => x[0])
.Select(g => (Length: g.Sum(x => x.Length), Char: g.Key))
.OrderByDescending(t => t.Length)
.ThenBy(t => t.Char)
.Select(t => $"{t.Length}-{t.Char}");
You're almost there. The cleanest way of doing it would be to make a more complex object with the properties you care about, use those to sort, then keep only what you want in the output. Like:
stringList
.GroupBy(x => x[0])
.Select(g => new {
Len = g.Sum(x => x.Length),
Char = g.Key,
Val = $"{g.Sum(x => x.Length)}-{g.Key}"
})
.OrderByDescending(x => Len)
.ThenBy(x => x.Char)
.Select(x => x.Val);
You can add a Select after the GroupBy to transform the groups into an anonymous object containing the things you want to sort by. Then you can use OrderByDescending and ThenBy to sort. After that, Select the formatted string you want:
stringList.GroupBy(x => x[0]) // assuming all strings are non-empty
.Select(g => new {
LengthSum = g.Sum(x => x.Length),
FirstChar = g.Key
})
.OrderByDescending(x => x.LengthSum)
.ThenBy(x => x.FirstChar)
.Select(x => $"{x.LengthSum}-{x.FirstChar}");
Alternatively, do it in the query syntax with let clauses, which I find more readable:
var query = from str in stringList
group str by str[0] into g
let lengthSum = g.Sum(x => x.Length)
let firstChar = g.Key
orderby lengthSum descending, firstChar
select $"{lengthSum}-{firstChar}";
I have a list of ints. I want to group the list and create a new list that contains only the grouped by number that meets a certain condition. this is what i have so far. the declarating for membersList is List
int rows = 5;
List<int> memberKeys = memberKeysList
.GroupBy(x => x)
.Where(x => x.Count() == rows)
.ToList();
Its complaining about converting from groupedby list to a list.
You need to Select the Key to get the number like:
List<int> memberKeys = memberKeysList.GroupBy(x => x)
.Where(x => x.Count() == rows)
.Select(grp => grp.Key)
.ToList();
If you are not going to explicitly select they Key (or the number), then the result of GroupBy clause would be IEnumerable<IGrouping<TKey, TElement>>
When using the below code it works fine to return a var that is filled with DataRows I can loop:
var GetSetRows = Order.AsEnumerable()
.GroupBy(r => r.Field<string>("Job_No"))
.Where(g => g.Count() > 1)
.Select(g => g.First());
but what I would like to do is return a List<string> instead.
I tried:
List<string> c_strLSetTitle = Order.AsEnumerable()
.GroupBy(r => r.Field<string>("Job_No"))
.Where(g => g.Count() > 1)
.Select(g => g.First().ToString()).ToList();
but this returns a list filled with elements that say System.Data.DataRow, but it does return the correct amount, i.e. that amount of items that I am expecting to be returned.
g.First() returns object of type DataRow. Then you are calling ToString() which returns the type name System.Data.DataRow. At the end you have a list of type names.
If you want to select a particular column, then project group of rows into value of some field of (first) row:
g.First().Field<string>("FieldName")
Or you can use grouping key if you want to return values of Job_No filed:
List<string> c_strLSetTitle = Order.AsEnumerable()
.GroupBy(r => r.Field<string>("Job_No"))
.Where(g => g.Count() > 1)
.Select(g => g.Key).ToList();
That will return values of duplicated Job_No fields.
Because g is a collection of DataRow objects, so
.Select(g => g.First().ToString())
returns a collection of the string System.Data.DataRow
If you want to extract a field from each datarow, then use:
.Select(g => g.First().Field<{type}>("{fieldname}").ToString())
try this
List<string> c_strLSetTitle = Order.AsEnumerable()
.GroupBy(r => r.Field<string>("Job_No"))
.Where(g => g.Count() > 1)
.Select(g => g.Key).ToList();
I have a list of Objects, where every object has a "Name" and different other stuff. I want to filter out those objects who don't have a unique name in that List.
Is there a LINQ Statement where I can "Union()" all the resulting groups and just return a IEnumerable of my objects?
Like
IEnumerable<MyObject> Results = (from x in Objects
group x by x.Name into g
where g.Count() > 1
select g)
.COMBINE_OR_WHATEVER();
Thanks!
Yes, there is. You can use SelectMany.
IEnumerable<MyObject> Results = (from x in Objects
group x by x.Name into g
where g.Count() > 1
select g)
.SelectMany(x => x);
I think you want only the object with unique names ("I want to filter out those objects who don't have a unique name in that List"):
var result = Objects.GroupBy(o => o.Name)
.Where(grp => grp.Count() == 1)
.SelectMany(grp => grp);
Here's the scenario:
Given a List of Outputs each associated with an integer based GroupNumber. For each distinct GroupNumber within the List of Outputs starting with the lowest GroupNumber (1). Cycle through that distinct group number set and execute a validation method.
Basically, starting from the lowest to highest group number, validate a set of outputs first before validating a higher groupnumber set.
Thanks,
Matt
There's almost too many ways to solve this:
Here's one for a void Validate method.
source
.GroupBy(x => x.GroupNumber)
.OrderBy(g => g.Key)
.ToList()
.ForEach(g => Validate(g));
Here's one for a bool Validate method.
var results = source
.GroupBy(x => x.GroupNumber)
.OrderBy(g => g.Key)
.Select(g => new
{
GroupNumber = g.Key,
Result = Validate(g),
Items = g.ToList()
})
.ToList();
If you need them as groups:
var qry = source.GroupBy(x=>x.GroupNumber).OrderBy(grp => grp.Key);
foreach(var grp in qry) {
Console.WriteLine(grp.Key);
foreach(var item in grp) {...}
}
If you just need them ordered as though they are grouped:
var qry = source.OrderBy(x=>x.GroupNumber);