Home > Back-end >  LINQ for equivalent for-loop on multi-level nested collection, extracting index information
LINQ for equivalent for-loop on multi-level nested collection, extracting index information

Time:12-30

I have an instance variable _foo declared like so -

List< Dictionary<int, HashSet<int> > > _foo;

Yes, it is a messy data structure that is a List of Dictionaries whose key is an integer and its associated value is a HashSet of integers.

I am wondering whether a LINQ expression could be written that would do the equivalent of this code snippet:

var myList = new List<(int, int, int)>();
for (int xx = 0; xx < _foo.Count;   xx)
    foreach (var zzyy in _foo[xx])
        if (zzyy.Value.Count == 1)
            myList.Add((xx, zzyy.Value.First, zzyy.Key));

In other words, I would like to capture the indices of the elements in the List whose Dictionary-value (a HashSet) holds only a single value. Together with this index, I am also capturing the Dictionary-Key and the corresponding sole value within the Dictionary-value.

CodePudding user response:

The foreach can be written as

myList.AddRange(_foo[xx]
  .Where(zzyy => zzyy.Value.Count == 1)
  .Select(zzyy => (xx, zzyy.Value.First(), zzyy.Key)));

CodePudding user response:

In my mind the whole thing as a Linq would be

var myList = _foo.SelectMany((d,x) =>
  d.Where(kvp => kvp.Value.Count==1)
    .SelectMany(
      kvp => kvp.Value,
      (kvp, hsv) => (x,kvp.Key,hsv)
    )
).ToList();

..but honestly, I'm not sure it's clearer or more performant than what you have..

Consider that you have what you wrote, and it works, is easy to understand and debug.. whereas having to ask for outside assistance to convert it into a form that is harder to understand means it become much more difficult to debug if the need arises

I did consider that using partial LINQ might help:

var myList = new List<(int, int, int)>();
for (int fi = 0; fi < _foo.Count;   fi)
    foreach (var kvp in _foo[fi].Where(kvp => kvp.Value.Count == 1))
        myList.Add((fi, kvp.Value.First(), kvp.Key));

..but then then it's more wordy. You can see another answer that's had a stab at replacing the foreach with something longer and more convoluted

I'd leave it alone, chalk it up to one of those cases where "LINQ is a hammer, but not every problem is a nail".. Perhaps put the time at looking to see if you can reduce this convoluted nested "list of dictionaries of hashsets" data structure you've got into something easier to work with

  • Related