Kees C. Bakker
Kees C. Bakker

Reputation: 33391

How to partition an array into multiple arrays with LINQ?

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

Answers (5)

Tim Schmelter
Tim Schmelter

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

Hari Prasad
Hari Prasad

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

Leonard Klausmann
Leonard Klausmann

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

Charles Mager
Charles Mager

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

Ren&#233; Vogt
Ren&#233; Vogt

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

Related Questions