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

StackOverflow https://stackoverflow.com/questions/237377

Вопрос

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

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);

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

Это было полезно?

Решение

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

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"));

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

Если вы просто используете пример как способ изучения 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);
   }
}

По-моему, все в порядке.Вы могли бы сохранить пару символов, изменив выбор на:

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

В списке коллекций также есть метод 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 будет повторяться от первого к последнему), но это не обязательно будет иметь место с другими коллекциями (List, Dictionary и т.д.), Где 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 будет соблюдать порядок выполнения последней операции...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top