2013-06-05 2 views
2

У меня есть объект в C#, который имеет несколько свойств:Получить объекты из коллекции с Linq

// Pseudo class 
public class 
{ 
    Id; 
    To; 
    From; 
} 

У меня есть много экземпляров этого класса в Collection. Что может выглядеть следующим образом:

object 1: 
    Id: 1 
    To: "PathA" 
    From: "PathB" 

object 2: 
    Id: 2 
    To: "PathB" 
    From: "PathC" 

object 3: 
    Id: 3 
    To: "PathC" 
    From: "PathA" 

Теперь то, что я хочу сделать, это получить все элементы из коллекции, что, когда значение To не появляется в From в любом из объектов. Что бы привести следующие:

object 1: 
    Id: 1 
    To: "PathA" 
    From: "PathB" 

object 2: 
    Id: 2 
    To: "PathB" 
    From: "PathC" 

Поскольку последний объект Id: 3 имеет PathA в From собственности, которая уже существует где-то в To собственности.

Как это сделать с помощью запроса Linq?

ответ

2

Ну, как решить эту проблему? Во-первых, вы можете создать индекс всех значений To. Затем отфильтровать последовательность, основанную на From собственности ...

Что-то вроде:

var tos = new HashSet<string>(collection.Select(item => item.To)); 
var filtered = collection.Where(item => !tos.Contains(item.From)); 

Вы могли бы хотеть, чтобы проверить, если создать HashSet действительно работает, как это, или если вам нужно построить его по-разному ... Но ты получил идею. Наборы являются эффективными, если tos получает довольно долго, так как вы будете проверять это много ...

+0

'действительно работает как это' - он делает, один из конструкторов HashSet принимает значение IEnumerable ', так как Linq' Select' return 'IEnumerable ' это будет компилироваться и работать.Я также люблю метод расширения MoreLINQ 'ToHashSet()', вам не нужно объявлять '' общий параметр, все выведено. –

+0

@IlyaIvanov :) приятно. Мне нравится, когда структура работает так, как ожидалось! –

0
var list = collection.Select(c=>c.To).Distinct().ToList(); 
var result = collection.Where(c=>!list.Contains(c.From)).ToList(); 
1

Произнесите коллекция объектов выглядит следующим образом:

var objects = { object1, object2, object3 } 

Затем вы хотите:

var result = objects.Where(o => !objects.Select(x => x.From).Contains(o.To)); 

Если речь идет о большом наборе данных, это может быть умным, чтобы кэшировать и сохранить суб-выбор «От» путей:

var fromPaths = new HashSet<string>(objects.Select(x => x.From)); 
var result = objects.Where(o => !fromPaths.Contains(o.To)) 
0

Если вы присоединитесь коллекцию обратно на себя, используя К и С в соответствующих ключей, вы можете установить, какие элементы «присоединились» через К/С и исключить их:

var itemsThatAreConnected = 
    collection.Join(collection, x => x.To, x => x.From, (a,b) => a); 
var unconnected = collection.Except(itemsThatAreConnected); 
1

Во-первых, ваш образец на самом деле не соответствует тексту вопроса, так как все объекты-образцы имеют To, соответствующие некоторым другим From. Но предполагая, что вопрос-текст является правильным и образец является неправильным:

Как насчет с group-join:

var query = from obj in collection 
      join fromObj in collection 
       on obj.To equals fromObj.From 
       into objGroup 
      where !objGroup.Any() 
      select obj; 

В качестве альтернативы, построить множество различных Froms первых:

var distinctFroms = new HashSet<string>(collection.Select(item => item.From)); 

var query = from obj in collection 
      where !distinctFroms.Contains(obj.To) 
      select obj;