Используя LINQ, как выбрать элементы по определенным индексам? - PullRequest
4 голосов
/ 23 сентября 2010

Если у меня есть IEnumerable<Foo> allFoos и IEnumerable<Int32> bestFooIndexes, как я могу получить новый IEnumerable<Foo> bestFoos, содержащий Foo записи из allFoos по индексам, указанным bestFooIndexes?

Ответы [ 6 ]

12 голосов
/ 23 сентября 2010
var bestFoos = bestFooIndexes.Select(index => allFoos.ElementAt(index));

Если вы беспокоитесь о производительности и у вас большие коллекции:

List<Foo> allFoosList = allFoos.ToList();
var bestFoos = bestFooIndexes.Select(index => allFoosList[index]);
11 голосов
/ 23 сентября 2010

Ответ Елисея, безусловно, будет работать, но он может быть очень неэффективным ... это зависит от того, чем реализуется allFoos.Если это реализация IList<T>, ElementAt будет эффективна - но если это на самом деле результат (скажем) запроса LINQ to Objects, то запрос будет перезапущен для каждого индекса.Так что может эффективнее написать:

var allFoosList = allFoos.ToList();
// Given that we *know* allFoosList is a list, we can just use the indexer
// rather than getting ElementAt to perform the optimization on each iteration
var bestFoos = bestFooIndexes.Select(index => allFoosList[index]);

Вы можете сделать это только при необходимости, конечно:

IList<Foo> allFoosList = allFoos as IList<Foo> ?? allFoos.ToList();
var bestFoos = bestFooIndexes.Select(index => allFoosList[index]);
2 голосов
/ 23 сентября 2010

Вы можете сделать метод расширения следующим образом:

public IEnumerable<T> ElementsAt(this IEnumerable<T> list, IEnumerable<int> indexes)
{
     foreach(var index in indexes)
     {
           yield return list.ElementAt(index);
     }

}

Тогда вы можете сделать что-то вроде этого

var bestFoos = allFoos.ElementsAt(bestFooIndexes);
1 голос
/ 23 сентября 2010

Другое решение, основанное на соединении:

var bestFoos = from entry in allFoos
                               .Select((a, i) = new {Index = i, Element = a})
           join index in bestFooIndexed on entry.Index equals index
           select entry.Element;
1 голос
/ 23 сентября 2010

Ответ Джона Скита / Елисея - путь.

Вот немного другое решение, по всей вероятности, менее эффективное:

var bestFooIndices = new HashSet<int>(bestFooIndexes);
var bestFoos = allFoos.Where((foo, index) => bestFooIndices.Contains(index));

Повторения, содержащиеся в bestFooIndexes, не дадут дубликатов в результате. Кроме того, элементы в результате будут упорядочены по порядку перечисления в allFoos, а не по порядку, в котором они присутствуют в bestFooIndexes.

0 голосов
/ 23 сентября 2010

var bestFoosFromAllFoos = allFoos.Where (s) => bestFoos.Contains (s));

...