Home > Software engineering >  LINQ and Sorting into sequential Collection with random access capability
LINQ and Sorting into sequential Collection with random access capability

Time:12-03

I have this code:

SortedList<int, SortedList<int, SimulationPoint>> sl = new SortedList<int, SortedList<int, SimulationPoint>>();

for(int i=0; i<source.Reflections 1; i  )
{
    sl.Add(i, new SortedList<int, SimulationPoint>());
}

var q = source.SimulationResult.Where(x => !x.Value.hasHit);

foreach (var qa in q) 
{  
    sl[qa.Key.Item2].Add(qa.Key.Item1, qa.Value); 
}

I wanted to generate a sorted output of the collection source.SimulationResult, which is a Dictionary<(int, int), SimulationPoint>. (This dictionary was generated using a Parallel.For() loop, so all the items are in random order.)

Dictionary Key: Just the Ray number emitted from the source (e.g. 0->100) and the Reflection number (e.g. 0->10) as it bounces around the scene: (int Ray, int Reflection).

Dictionary Value: The SimulationPoint is an output point of a ray-tracing procedure, the most important element of which is that it contains a field bool hasHit that indicates if the point, well, hit an element in the scene or not. (We're looking for those errors here, hence source.SimulationResult.Where(x=>!x.Value.hashit);) (FWIW, this struct SimulationPoint also contains the Ray & Reflection data.)

Generally, this works. But I really like the LINQ syntax and one-liner concept, as it can avoid multiple nested loops. Does anyone have an idea how this can be simplified using the LINQ extensions?

Please keep in mind that I'd like to be able to jump around at the user's choice within the sl collection, this is the problem I'm having with the IGrouping<int, SimulationPoint> outputs from the GroupBy(x=>x.Key.Item2, x=>x.Value) method - it's only accessible sequentially using a foreach loop, even when ordering it with OrderBy(x.Key.Item2).ThenBy(x.Key.Item1).

CodePudding user response:

To simplify the code using LINQ, you can use the ToList method to convert the output of the Where clause to a List, which you can then sort using the OrderBy and ThenBy methods. Here's an example:

// Get the list of simulation points where hasHit is false
var q = source.SimulationResult.Where(x => !x.Value.hasHit).ToList();

// Sort the list by Ray and Reflection number
var sortedList = q.OrderBy(x => x.Key.Item1).ThenBy(x => x.Key.Item2).ToList();

// Create a SortedList for each Reflection number, and add the corresponding
// simulation points to it
SortedList<int, SortedList<int, SimulationPoint>> sl = 
    new SortedList<int, SortedList<int, SimulationPoint>>();

foreach (var simPoint in sortedList)
{
    if (!sl.ContainsKey(simPoint.Key.Item2))
    {
        sl.Add(simPoint.Key.Item2, new SortedList<int, SimulationPoint>());
    }

    sl[simPoint.Key.Item2].Add(simPoint.Key.Item1, simPoint.Value);
}

This code will generate a SortedList called sl that contains a SortedList for each Reflection number, and each of these SortedLists will contain the SimulationPoints for that Reflection number sorted by Ray number. You will be able to access any element of sl using the SortedList's indexer, allowing you to jump around within the collection.

CodePudding user response:

I suggest adding an extension method (group) analogous to ToDictionary to do ToSortedList. Then with that extension method available, you can use GroupBy (which is internally creating a Dictionary...) to create the SortedLists. Internally you are essentially running over the source data twice, but it doesn't seem like you are talking about a lot of data.

var sl2 = q.GroupBy(kvp => kvp.Key.Reflection) // group by outer SortedList Key
           .ToSortedList(kvpg => kvpg.Key, // outer SortedList Key (Reflection)
                         // outer SortedList Value (SortedList: Ray -> SimulationPoint)
                         kvpg => kvpg.ToSortedList(kvp => kvp.Key.Ray, // inner SortedList Key (Ray)
                                                   kvp => kvp.Value) // inner SortedList Value (SimulationPoint)
                        );

Here are the extension method definitions:

public static class IEnumerableExt {
    public static SortedList<TKey, TValue> ToSortedList<TItem, TKey, TValue>(this IEnumerable<TItem> items, Func<TItem, TKey> keyFn, Func<TItem, TValue> valueFn) {
        var ans = new SortedList<TKey, TValue>();
        foreach (var item in items)
            ans.Add(keyFn(item), valueFn(item));
        return ans;
    }
    public static SortedList<TKey, TValue> ToSortedList<TKey, TValue>(this IEnumerable<TValue> items, Func<TValue, TKey> keyFn) {
        var ans = new SortedList<TKey, TValue>();
        foreach (var item in items)
            ans.Add(keyFn(item), item);
        return ans;
    }
    public static SortedList<TKey, TKey> ToSortedList<TKey>(this IEnumerable<TKey> items) {
        var ans = new SortedList<TKey, TKey>();
        foreach (var item in items)
            ans.Add(item, item);
        return ans;
    }
}
  • Related