public Dictionary<string, Dictionary<int, List<int>>> fuBenNPCDictionary;
。。。something;
IEnumerable<(string fuben, int pos)> query = from string fuben in fuBenNPCDictionary.Keys
let fubendict = fuBenNPCDictionary[fuben]
from int pos in fubendict.Keys
where fubendict[pos].Contains(npc.ID)
select (fuben, pos);
if (query.Count() > 0)
foreach ((string fuben, int pos) in query)
{
placestr = "在" + jsonData.instance.SceneNameJsonData[fuben]["MapName"].str.ToCN() + "的第" + pos.ToString() + "位置";
}
This query was originally a manual foreach, and then VS turned it into a Linq form. I'm not very good at linq and would like to convert it to Linq method lambda syntax.
IEnumerable<(string key, int pos)> query = fuBenNPCDictionary.Keys
.SelectMany(fuben => fuBenNPCDictionary[fuben]
.Where(fubenDict => fubenDict.Value.Contains(npc.ID))
.Select(fubenDict => (fuben, fubenDict.Key)));
If you're unfamiliar with SelectMany
, it might be easier to think about what this code will do instead for now:
IEnumerable<IEnumerable<(string key, int Key)>> query2 = fuBenNPCDictionary.Keys
.Select(fuben => fuBenNPCDictionary[fuben]
.Where(fubenDict => fubenDict.Value.Contains(npc.ID))
.Select(fubenDict => (fuben, fubenDict.Key)));
So first we start with a Select
on the fuBenNPCDictionary.Keys
, taking each string key, and mapping it to the return of the subsequent code. In other words, for each key in the dict, do some sort of calculation or procedure, and give me a new list with the return from that procedure.
Inside this Select
we can think about just what we're doing with one of the keys. We'll take the corresponding value to the key: fuBenNPCDictionary[fuben]
, which is now the Dictionary<int, List<int>>
. We want to filter the values in here to only include relevant List<int>
s so we'll use the Where
. Next we want to take those filtered List
s and Select
the tuple (fuben, fubenDict.Key)
. Note that we get fubenDict
from the direct scope of our current Select
, but we can grab fuben
from within the scope of our parent Select
. It's a little easier to see that this is valid if we had written the statement like below (omitting the Where
for brevity):
fuBenNPCDictionary.Keys.Select(fuben =>
{
return fuBenNPCDictionary[fuben]
// Note this is still inside the curly braces in which `fuben` is still in scope.
.Select(fubenDict => (fuben, fubenDict.Key));
});
Putting this all together, the last thing left is that our query2
contains an extra level of nesting that we didn't want: it's of type IEnumerable<IEnumerable<(string key, int Key)>>
instead of IEnumerable<(string key, int pos)>
. So instead of a single list we have a list of lists. The answer to this is to change the outer Select
to SelectMany
instead. A simple example for SelectMany
would be that if you had an array that looked like
[ [1, 2], [1] ]
You could do a SelectMany(x => x)
to get [1, 2, 1]
, flattening the jagged array to a single array.