Reputation: 33391
In order to explain the problem I've created a simplified example. In real life the data class is somewhat more complicated. Consider the following data class:
public class Data
{
public Data(string source, string path, string information)
{
this.Source = source;
this.Path = path;
this.Information = information;
}
public string Source { get; set; }
public string Path { get; set; }
public string Information { get; set; }
}
Now consider the following array:
var array = new Data[] {
new Data("MS", @"c:\temp\img1.jpg", "{a}"),
new Data("IBM", @"c:\temp\img3.jpg", "{b}"),
new Data("Google", @"c:\temp\img1.jpg", "{c}"),
new Data("MS", @"c:\temp\img2.jpg", "{d}"),
new Data("MS", @"c:\temp\img3.jpg", "{e}"),
new Data("Google", @"c:\temp\img1.jpg", "{f}"),
new Data("IBM", @"c:\temp\img2.jpg", "{g}")
};
I would like to process the data by partitioning it on the Path
and sorting each partition on Source
. The output needs to be like:
c:\temp\img1.jpg
"Google": "{c}"
"IBM": "{f}"
"MS": "{a}"
c:\temp\img2.jpg
"IBM": "{g}"
"MS": "{d}"
c:\temp\img3.jpg
"IBM": "{b}"
"MS": "{e}
How can I create these partitions with LINQ?
Here you can play with the code: https://dotnetfiddle.net/EbKluE
Upvotes: 2
Views: 596
Reputation: 460138
You can use Enumerable.GroupBy
to group by the Path
property:
var pathPartitions = array.GroupBy(x => x.Path);
foreach(var grp in pathPartitions)
{
Console.WriteLine(grp.Key);
var orderedPartition = grp.OrderBy(x => x.Source);
foreach(var x in orderedPartition )
Console.WriteLine($"\"{x.Source}\": \"{x.Information}\"");
}
If you want to create a collection you could create a Tuple<string, Data[]>[]
:
Tuple<string, Data[]>[] pathPartitions = array
.GroupBy(x => x.Path)
.Select(g => Tuple.Create(g.Key, g.OrderBy(x => x.Source).ToArray()))
.ToArray();
or a Dictionary<string, Data[]>
:
Dictionary<string, Data[]> pathPartitions = array
.GroupBy(x => x.Path)
.ToDictionary(g => g.Key, g => g.OrderBy(x => x.Source).ToArray());
Upvotes: 1
Reputation: 16956
You could use GroupBy
and do this.
var results = array
.GroupBy(x=>x.Path)
.Select(x=>
new
{
Path =x.Key,
values=x.Select(s=> string.Format("{0,-8}:{1}", s.Source, s.Information))
.OrderBy(o=>o)
})
.ToList();
Output:
c:\temp\img1.jpg
Google :{c}
Google :{f}
MS :{a}
c:\temp\img3.jpg
IBM :{b}
MS :{e}
c:\temp\img2.jpg
IBM :{g}
MS :{d}
Check this fiddle
Upvotes: 1
Reputation: 215
I would recommend the Group-by function of lync. For your case:
var queryImageNames =
from image in array // <-- Array is your name for the datasource
group image by image.Path into newGroup
orderby newGroup.Key
select newGroup;
foreach (var ImageGroup in queryImageNames)
{
Console.WriteLine("Key: {0}", nameGroup.Key);
foreach (var image in ImageGroup )
{
Console.WriteLine("\t{0}, {1}", image.Source, image.Information);
}
}
Upvotes: 1
Reputation: 26213
You can use LINQ's OrderBy
and GroupBy
to sort your items by Source
and group your ordered items by Path
:
var partitioned = array
.OrderBy(data => data.Source)
.GroupBy(data => data.Path);
See this fiddle for a demo.
Upvotes: 7
Reputation: 43886
You can use GroupBy
and OrderBy
like this:
Dictionary<string, Data[]> result =
array.GroupBy(d => d.Path)
.ToDictionary(g => g.Key, g => g.OrderBy(d => d.Source).ToArray());
This gives you a dictionary with Path
as keys. Each value is an array of Data
that have this Path
and are sorted by their Source
.
Upvotes: 1