I have a dictionary in the form of Dictionary<int, List<int>>
The problem is that I need to group the keys together into buckets defined by the value (List<int>
). It is easier to explain with an example.
Consider the dictionary:
{
1: [5,4]
2: [4]
3: [10]
}
Out of this, I need the dictionary:
{
5: [1]
4: [2, 1]
10: [3]
}
The approach I took for this is to basically flatten the input dictionary, producing many key value pairs
1: 5
1: 4
2: 4
3: 10
And then grouping on the value (getting the correct result.)
The problem with this approach is that it takes a long time, and I cannot parallelize it.
The LINQ query I wrote for this is:
Dictionary<int, List<int>> test = <Some init data set>;
test.SelectMany(x => x.Value.Select(y => Tuple.Create(x.Key, y)))
.GroupBy(x=>x.Item2).ToDictionary(x=>x.Key, x=>x.ToList());
Is there a better / more efficient way to do this? My concern is that by flattening the list in the value operand, I am creating a lot of records, and therefore this algorithm will probably not scale very well?
Thanks!
EDIT:
More information:
Here is some background information about the problem as a whole.
The dictionary is actually a def-use chain; where the key is a reference to a statement that define some data, and the value is a list of references to statements use the data produced by the statement from this definition. Since the code that this optimizer works with is obfuscated, the def-use chain is unusually large (ie, not consistent with what a def-use chain would be on code that someone would normally write.) Therefore, there are an unusual amount of definitions in the def-use chain.
I am trying to build a graph so I can ask: I need this statement here, so what other statements do I also need to carry along with me to keep that statement valid (FWIW, the code is in Static Single Assignment form.)
So to build this graph, I create a Node for each statement in the application. Then I:
- Flatten the def-use chain (list of, for each statement that produces data, where is that data used)
- group by uses (For each use of produced data, what are the required definitions)
- For each use, connect to its respective required definition
Now we essentially have the graph, I can forward traverse at any node to find all statements I need to keep for that node to remain "valid". I used some tricks to make building and traversing the graph very cheap, but #2 is by far the bottle-neck here.
The code that I am working with (ie, statements etc) are purposely crafted to make computations like this not cheap. Ie, this is not normal code written by a person.
Also, this application has a lot of resources to its disposal (many cores 30+, 30GB+ memory.) So really, I am looking for an algorithm that can scale (ie, with a even larger def-use chain.)