I have object list (name is list) with e.g. next values:
[0] {Id='04239',Color='03',MatPre='145698',Stz=210,Spp=1}
[1] {Id='04239',Color='03',MatPre='145698',Stz=210,Spp=3}
[2] {Id='04239',Color='KB',MatPre='145698',Stz=210,Spp=3}
[3] {Id='04239',Color='KB',MatPre='145698',Stz=210,Spp=2}
[4] {Id='04239',Color='03',MatPre='145698',Stz=210,Spp=4}
Result or new list that I whant to get is list with v items:
[0] {Id='04239',Color='03',MatPre='145698',Stz=210,Spp=3}
[1] {Id='04239',Color='03',MatPre='145698',Stz=210,Spp=4}
[2] {Id='04239',Color='KB',MatPre='145698',Stz=210,Spp=3}
I would need something like this
var test = list.GroupBy(x => new { x.Color })
.Where(x => x.Spp is greater than first
smaller x.Spp in same
group of Color)
.SelectMany(x => x).ToList();
I don't know how to do this.
This should do it, although calling Min every time might not be efficient, you might consider query syntax to make it better:
list.GroupBy(x => x.Color)
.SelectMany(g => g.Where(x => x.Spp > g.Min(_ => _.Spp));
Related
Is there a elegant way of doing following in LINQ or should I write an extension for this
i have a list of objects that need to be grouped by startdate
lets say
09.00,
13.00,
13.00,
13.00,
15.00,
var groupedStartDates = startdate.groupby(x => x.StartDate);
I need to have maximum size of group to be 2.
Expected result is
var groupedStartDates = startDate.GroupBy(x => x.StartDate);
List
list1 {09.00}
list2 {13.00; 13.00}
list3 {13.00}
list4 {15.00}
After the initial grouping you can then group by the index (in the groups) divided by 2 to do a further grouping, then use SelectMany to flatten that back out.
var result = startDate.GroupBy(x => x.StartDate)
.SelectMany(grp => grp.Select((x,i) => new{x,i})
.GroupBy(a => a.i / 2)
.Select(sgrp => sgrp.Select(a => a.x)));
Here's a break down of what's going on. Note curly brackets will represent collections and square will represent object with multiple properties.
Initial data
09.00, 13.00, 13.00, 13.00, 15.00
After GroupBy(x => x.StartDate)
[Key:09.00, {09.00}], [Key:13.00, {13.00, 13.00, 13.00}], [Key:15.00, {15.00}]
Now it's going to operate on each group, but I'll show the results for all of them at each step.
After the Select((x,i) => new{x,i})
{[x:09.00, i:0]}, {[x:13.00, i:0], [x:13.00, i:1], [x:13.00, i:2]}, {[x:15.00, i:0]}
After the GroupBy(a => a.i / 2)
{[Key:0, {[x:09.00, i:0]}]}, {[Key:0, {[x:13.00, i:0], [x:13.00, i:1]}], [Key:1, {[x:13.00, i:2]}}, {[Key:0, {[x:15.00, i:0]}}
After the .Select(sgrp => sgrp.Select(a => a.x))
{{09.00}}, {{13.00, 13.00}, {13.00}}, {{15.00}}
And finally the SelectMany will flatten that to.
{09.00}, {13.00, 13.00}, {13.00}, {15.00}
Note that each line represents a collection, but I didn't put curly braces around them as I felt it made it even harder to read.
Or with an extension method
public static IEnumerable<IEnumerable<T>> Bin<T>(this IEnumerable<T> items, int binSize)
{
return items
.Select((x,i) => new{x,i})
.GroupBy(a => a.i / binSize)
.Select(grp => grp.Select(a => a.x));
}
You can make it a little nicer.
var result = startDate
.GroupBy(x => x.StartDate)
.SelectMany(grp => grp.Bin(2));
Update: As of .Net 6 they have added the new Linq method Chuck that does the same thing as my Bin method above. So now you can do
var result = startDate
.GroupBy(x => x.StartDate)
.SelectMany(grp => grp.Chunk(2));
If I understand your question correctly, you can use Take:
var result= startDate.GroupBy(x => x.StartDate)
.Select(x => x.Take(2))
.ToList();
Each group will contains at most 2 members and additional items of groups will not return.
I have array of lists (string typed):
List<string>[] nodesAtLevel = new List<string>[20];
e.g:
[0] - List: "Hi", "There"
[1] - List: "Hi", "There", "Someone"
[2] - List: "Hi"
I need to write a LINQ operation that would return the array index of the biggest list.
Regard the example above, the LINQ operation should return 1 (because it has 3 items).
I know I should use "Where" and "Max" functions but I can't figure out how.
Use this query. First, you want to create a collection of objects that holds information about index of a list in the array and count of its items. Then, order this new collection by Count, select the first or last (depending on how you ordered the collection) and take an index.
var result = nodesAtLevel.Select((l, i) => new { Count = l.Count, Index = i })
.OrderByDescending(x => x.Count)
.First()
.Select(x => x.Index);
my version:
var max = nodesAtLevel.Select((l, i) => new { index = i, list = l })
.OrderBy(x => x.list.Count)
.Last().index;
I have a data set something like this:
2,Black
2,Blue
2,Red
1,Small
1,Medium
I need to convert this into the following:
2_0
2_1
2_2
1_0
1_1
The LINQ query I have at the moment uses an index for the second number, however it doesn't reset to 0 when changing from 2_ to 1_. I've tried using a GroupBy, but I can't get the results I need - can anyone help?
IEnumerable<string> output = input
.GroupBy(i => i.Num)
.SelectMany(grp => grp.Select((item, idx) => string.Format("{0}_{1}", grp.Key, idx)));
You can group by the number and use the version of Select() that provides the index:
var result = data.GroupBy(x => x.Number,
(key, g) => g.Select((_, i) => string.Format("{0}_{1}", key, i)))
.SelectMany(x => x);
Note that this might behave differently than you'd expect if the same numbers aren't contiguous: e.g, 2, 2, 2, 1, 1, 2, 2.
I have List<Dictionary<string, string>> object with some datas in it.
/* Values in the list will be like
[0] -
aaa - aaaValue1 (Key, Value)
bbb - bbbValue1
ccc - cccValue1
ddd - dddValue1
[1] -
aaa - aaaValue2 (Key, Value)
bbb - bbbValue2
ccc - cccValue2
ddd - dddValue2
and so on */
I want to get the distinct values( List<string> ) in the dictionary where the key is equal to "ccc" and the value of the key "bbb" is equal to "bbbValue1".
Expected Result:
Return a string list contains the dictionary value where key is equal to "ccc" and the value of the key "bbb" is equal to "bbbValue1" in the List<Dictionary<string, string>>.
I think you want:
var result = testData.Where(dict => dict.ContainsKey("EmpNo"))
.Select(dict => dict["EmpNo"])
.Distinct()
.ToList();
or if you want the result as a set:
var result = new HashSet<string>(from dict in testData
where dict.ContainsKey("EmpNo")
select dict["EmpNo"]);
EDIT:
You've changed your question completely, which isn't a nice thing to do (ask a new one instead), but to answer it in its current state:
var result = testData.Where(dict => dict.ContainsKey("ccc")
&& dict.ContainsKey("bbb")
&& dict["bbb"] == "bbbValue1")
.Select(dict => dict["ccc"])
.Distinct()
.ToList()
Think it will be better to flatten list like this:
testData.SelectMany(x => x)
.Where(x => x.Key == "EmpNo")
.Select(x => x.Value)
.Distinct()
.ToList();
I think this will give you the correct result:
var result = testData.SelectMany(dict => dict)
.Where(dict => dict.Key.Equals("ccc") || (d.Key.Equals("bbb") && d.Value.Equals("bbbValue1")))
.Select(d => d.Value).Distinct().ToList();
Suppose I have the array string[] weekDays = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" }; , and I want to find out the index of array elements containing 's'. How can I do this using Linq ?
I've tried int[] indexOfDaysContainingS = weekDays.Where(day => day.Contains("s")).Select((day, index) => index).ToArray();, but this returns 0,1,2 as presumably it's getting the index of the filtered IEnumberable<string> after the Where() clause instead. If I put the Select() first, then all I have is the index and can't filter by the days.
What do I need to change to make it work and return 1,2,3 instead ?
You could do it this way:
weekDays.Select((day, index) => new { Day = day, Index = index })
.Where(x => x.Day.Contains("s"))
.Select(x => x.Index)
.ToArray();
Not sure if this is optimal..
Patko's answer is the way to go in the general case.
Here are 2 more options:
// Idea only works with collections that can be accessed quickly by index.
int[] indices = Enumerable.Range(0, weekDays.Length)
.Where(index => weekDays[index].Contains("s"))
.ToArray();
With MoreLinq:
// Similar to Patko's idea, except using a 'named' type.
int[] indices = weekDays.AsSmartEnumerable()
.Where(item => item.Value.Contains("s"))
.Select(item => item.Index)
.ToArray();
This should work:
weekDays.Where(a => a.Contains("s")).Select((a, i) => i).ToArray();