Получение коллекции значений индекса с помощью запроса LINQ

Есть лучший способ сделать это?

string[] s = {"zero", "one", "two", "three", "four", "five"};

var x = 
s
.Select((a,i) => new {Value = a, Index = i})
.Where(b => b.Value.StartsWith("t"))
.Select(c => c.Index);

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
17
0
10 597
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Мне кажется, это нормально. Вы можете сохранить пару символов, изменив выбор на:

.Select((Value, Index) => new {Value, Index})

Спасибо - я не знал, что ты можешь это сделать - я думал, тебе нужно переназначить.

Guy 26.10.2008 05:07

Он называется «инициализатором проекции» - он в основном берет последнее подвыражение (которое должно быть полем или свойством) внутри выражения и использует его для имени. Таким образом, вы можете выполнить x.GetFoo (). Bar, и это будет эквивалентно Bar = x.GetFoo (). Bar.

Jon Skeet 26.10.2008 10:12

Если вы просто используете этот пример как способ изучить LINQ, проигнорируйте этот пост.


Мне неясно, действительно ли LINQ - лучший способ сделать это. Приведенный ниже код кажется более эффективным, поскольку создавать новый анонимный тип не требуется. Конечно, ваш пример может быть надуманным, и метод может быть более полезным в другом контексте, например, в структуре данных, где он может использовать преимущество индекса по значению, но приведенный ниже код достаточно прост и понятен (не думал требуется) и, возможно, более эффективен.

string[] s = {"zero", "one", "two", "three", "four", "five"};
List<int> matchingIndices = new List<int>();

for (int i = 0; i < s.Length; ++i) 
{
   if (s[i].StartWith("t"))
   {
      matchingIndices.Add(i);
   }
}

Спасибо за ответ. Я согласен, что так было бы эффективнее. Как вы уже догадались, это упрощенная версия чего-то более сложного, что «должно» быть сделано в LINQ в данном конкретном случае.

Guy 26.10.2008 08:23

И этот точный код работает только тогда, когда вы используете List вместо произвольного IEnumerable. В противном случае вам пришлось бы использовать foreach и отдельную локальную переменную.

Jon Skeet 26.10.2008 10:14
Ответ принят как подходящий

Вы можете легко добавить свой собственный метод расширения:

public static IEnumerable<int> IndexesWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    int index=0;
    foreach (T element in source)
    {
        if (predicate(element))
        {
            yield return index;
        }
        index++;
    }
}

Затем используйте его с:

string[] s = {"zero", "one", "two", "three", "four", "five"};
var x = s.IndexesWhere(t => t.StartsWith("t"));

В списке коллекций также есть метод FindIndex, для которого вы создаете метод удаления, который может возвращать индекс из коллекции. вы можете обратиться к следующей ссылке в msdn http://msdn.microsoft.com/en-us/library/x1xzf2ca.aspx.

Как насчет этого? Он похож на исходный плакат, но сначала я выбираю индексы, а затем создаю коллекцию, соответствующую критериям.

var x = s.Select((a, i) => i).Where(i => s[i].StartsWith("t"));

Это немного менее эффективно, чем некоторые другие ответы, поскольку список полностью повторяется дважды.

Я обсуждал эту интересную проблему с коллегой, и сначала я подумал, что решение JonSkeet отличное, но мой коллега указал на одну проблему, а именно: если функция является расширением IEnumerable<T>, то ее можно использовать там, где ее реализует коллекция.

С массивом можно с уверенностью сказать, что порядок, созданный с помощью foreach, будет соблюдаться (т.е. foreach будет повторяться от первого до последнего), но это не обязательно будет иметь место с другими коллекциями (список, словарь и т. д.), Где foreach не будет отражать обязательно «порядок входа». Но функция есть, и она может вводить в заблуждение.

В конце концов, я получил что-то похожее на ответ tvanfosson, но как метод расширения для массивов:

public static int[] GetIndexes<T>(this T[]source, Func<T, bool> predicate)
{
    List<int> matchingIndexes = new List<int>();

    for (int i = 0; i < source.Length; ++i) 
    {
        if (predicate(source[i]))
        {
            matchingIndexes.Add(i);
        }
    }
    return matchingIndexes.ToArray();
}

Надеюсь, List.ToArray соблюдает порядок последней операции ...

«Но функция есть, и она может вводить в заблуждение». - но это будет то же самое для любого из других методов LINQ, которые используют индексы, например .Select((item, index) => . Я не думаю, что с функцией Джона что-то не так, если вы понимаете, что получаете.

Rup 02.05.2012 16:01

@Rup С тех пор я получил больше опыта работы с LINQ и интерфейсом IEnumerable. Я согласен с тем, что если вы знаете, что делаете, и если функция определена, сюрпризов не будет. Одна из потенциальных опасностей - получить индексы из IEnumerable, созданного с помощью AsParallel. Эти индексы будут отражать состояние создания коллекции, но создание ее снова почти гарантированно даст другой результат. Индексы будут относиться к тому, чего не существует. В командной работе (или при повторном использовании функции позже), если это поведение непонятно, у вас будут проблемы.

MPelletier 02.05.2012 17:27

Я все еще думаю, что порядок вряд ли изменится, если вы не измените коллекцию, и что вам не следует использовать индексы, если это не имеет смысла для структуры. Но я не рассматривал AsParallel - здорово, спасибо.

Rup 02.05.2012 17:29

Другие вопросы по теме