Это рекурсия + пример LINQ, которая неэффективна?


У меня есть иерархия групп, и я хочу, чтобы получить коллекцию всех группах с наиболее низким уровнем (или листья, если мы будем смотреть на это как на дерево).

Я написал следующий код. Это неэффективно?

public static class FeatureWeightGroupExtensions
{
    public static IEnumerable<IFeatureWeightGroup> GetLeafGroups(this IFeatureWeightGroup featureWeightGroup)
    {
        return GetLeafGroupsRecursive(featureWeightGroup).ToList();
    }

    private static IEnumerable<IFeatureWeightGroup> GetLeafGroupsRecursive(IFeatureWeightGroup featureWeightGroup)
    {
        if (!featureWeightGroup.ChildGroups.Any())
            return Enumerable.Repeat(featureWeightGroup, 1);

        return featureWeightGroup.ChildGroups.Aggregate(Enumerable.Empty<IFeatureWeightGroup>(),
                                                        (allGroups, group) =>
                                                        allGroups.Concat(GetLeafGroupsRecursive(group)));
    }
}                      


2020
4
задан 24 февраля 2011 в 10:02 Источник Поделиться
Комментарии
2 ответа

return featureWeightGroup.ChildGroups.Aggregate(Enumerable.Empty<IFeatureWeightGroup>(),
(allGroups, group) =>
allGroups.Concat(GetLeafGroupsRecursive(group)));

Похоже, она может быть заменена:

return featureWeightGroup.ChildGroups
.SelectMany(g => GetLeafGroupsRecursive(group));

Что, вероятно, не будет намного лучше с точки зрения производительности, но выглядит чище.

4
ответ дан 24 февраля 2011 в 01:02 Источник Поделиться

Как уже было отмечено Snowbear и мой комментарий на его ответ, вы можете повысить производительность и читаемость с помощью метода SelectMany , а не конкатенацию.

Однако, я заметил, что вы используете вызова метода toList() в конце все равно. Это тянет на вопрос на благо, используя LINQ и все эти метода SelectMany итераторы в первую очередь. Используя производительность LINQ на жертвы на благо ленивостью, но вы не используете ленивый-оценка аспекта. Поэтому, если производительность является то, что вы после, тогда не использовать LINQ, что много:

public static class FeatureWeightGroupExtensions
{
public static IEnumerable<IFeatureWeightGroup> GetLeafGroups(this IFeatureWeightGroup featureWeightGroup)
{
var list = new List<IFeatureWeightGroup>();
populateList(list, featureWeightGroup);
return list;
}

private static void populateList(List<IFeatureWeightGroup> list, IFeatureWeightGroup featureWeightGroup)
{
if (!featureWeightGroup.ChildGroups.Any())
list.Add(featureWeightGroup);
else
foreach (var childGroup in featureWeightGroup.ChildGroups)
populateList(list, childGroup);
}
}

Это наиболее ориентированная на результат способом я могу думать, в то время как в то же время существенно легче читать, чем оригинал или от метода SelectMany альтернативы.

3
ответ дан 24 февраля 2011 в 03:02 Источник Поделиться