Linq - выберите, где предки содержат это? - PullRequest
0 голосов
/ 28 октября 2011

иногда я просто чувствую себя тупым ...

У меня есть простой класс:

public class myClass
{
    public long Id { get; set; }
    public long ParentChannelId { get; set; }
}

и у меня есть список, который содержит класс:

List<myClass> myItems = new List<myClass>

далее по коду, я наполняю список классами.

Теперь я хочу удалить элемент из списка. но, поскольку предмет может иметь детей, внуков и т.д ... Я хочу удалить все, что связано ..

думал о чем-то вроде: (псевдокод)

var List<myClass> itemsToDelete = myItems.Where(i => i.Ancestors.Contains(myItemId));

но у меня действительно нет мозгов, чтобы знать, как написать это точно ...: \ у меня есть функция .Ancestors ... просто нужна помощь с лямбда линком

public List<Channel> Ancestors
{
    get
    {
        List<MyCms.Content.Channels.Channel> result = new List<MyCms.Content.Channels.Channel>();

        Channel channel = this;

        while (channel != null)
        {
            result.Add(channel);
            channel = myChannels.Where(c => c.ParentChannelId == this.Id).First();
        }
        result.Reverse();

        return result;
    }
}

РЕДАКТИРОВАТЬ: думаю, я не объяснил себя, как я должен ... У меня есть все свойства, такие как предки, дети, родители и т. д. я хочу выбрать все классы, которые могут содержать определенный класс ...

Ответы [ 2 ]

2 голосов
/ 28 октября 2011

Я перечитал ваш вопрос, особенно последнюю часть, где вы сказали, что у вас уже есть .Ancestors, и теперь это имеет больше смысла.

Сделайте это, чтобы получить список элементов для удаления:

List<MyClass> itemsToDelete = myItems
    .Where(i => i.Id == myItemId)
    .SelectMany(i => i.Ancestors)
    .Concat(myItems) // Want to delete these too, not just the ancestors
    .ToList()
    ;

Затем вы можете foreach просмотреть результаты и удалить их из исходного списка.

Я бы предложил оставить их в Dictionary<int, MyClass> или HashSet<MyClass>.списка, поскольку удаление будет в порядке быстрее.

Для HashSet вам придется реализовать Equals и GetHashCode или создать реализацию IEqualityComparer<MyClass>чтобы предоставить эти методы.

Перед редактированием:

Я бы не написал свой код таким образом.Я бы просто создал Dictionary<int, MyClass> вместо списка.Он будет выполнять поиск намного быстрее, чем все, что связано с обходом предков / деревьев.

Но вот как выполнить то, что вы пытаетесь выполнить:

Если вы используете Linq to Objects (в отличие от Linq для SQL или Linq для сущностей), создайте свойство с именем Parent для MyClass правильного типа, вместо того, чтобы пытаться связать их с помощью Id.

Затем вы можете сделатьсвойство Ancestors довольно легко:

public IEnumerable<MyClass> Ancestors
{
    get
    {
        MyClass current = this;

        while(current != null)
        {
            current = current.Parent;
            yield return current;
        }
    }
}

Если вы не можете редактировать класс, создайте метод расширения с именем GetAncestors.

Тогда вы можете использовать что-то очень похожее накод, который вы написали в своем вопросе:

List<MyClass> itemsToDelete = myItems
    .Where(i => i.Ancestors.Any(a => a.Id == myItemId))
    .ToList();

Linq to Entities

Если вы используете Linq to Entities, создайте свойство навигации типа MyClass дляперейдите к родителю и сделайте то же самое.Обратите внимание, что это может вызвать повторные запросы.Не уверен, что Linq может или будет переведен в иерархический запрос.

1 голос
/ 28 октября 2011

Вот как я бы это сделал, используя метод hashset и RemoveAll.

var itemsToDelete = new HashSet<myClass>(otherItems);
myItems.RemoveAll(i => itemsToDelete.Contains(i));

Метод RemoveAll
http://msdn.microsoft.com/en-us/library/wdka673a.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...