Действительно ли урожай полезен за пределами LINQ?

Самый короткий путь (без необходимости загрузки сторонних разработчиков) - использовать PowerShell.

set "str=The quick brown fox"
for /f "usebackq delims=" %%I in (`powershell "\"%str%\".toUpper()"`) do set "upper=%%~I"

Более быстрый способ, но при использовании меньшего кода, чем любое чистое пакетное решение, - это использовать WSH.

@if (@CodeSection == @Batch) @then
@echo off & setlocal

set "str=The quick brown fox"
for /f "delims=" %%I in ('cscript /nologo /e:JScript "%~f0" "%str%"') do set "upper=%%~I"
set upper
goto :EOF

@end // end Batch / begin JScript hybrid
WSH.Echo(WSH.Arguments(0).toUpperCase());

И, конечно, вы можете легко сделать любую функцию, чтобы вы могли call ее несколько раз по мере необходимости.

@if (@CodeSection == @Batch) @then
@echo off & setlocal

call :toUpper upper1 "The quick brown fox"
call :toUpper upper2 "jumps over the lazy dog."
set upper
goto :EOF

:toUpper <return_var> <str>
for /f "delims=" %%I in ('cscript /nologo /e:JScript "%~f0" "%~2"') do set "%~1=%%~I"
goto :EOF

@end // end Batch / begin JScript hybrid
WSH.Echo(WSH.Arguments(0).toUpperCase());

Или, если вы хотите быть на самом деле это может быть неприятно, вы можете злоупотреблять сообщением об ошибке команды tree следующим образом:

@echo off & setlocal

set upper=
set "str=Make me all uppercase!"
for /f "skip=2 delims=" %%I in ('tree "\%str%"') do if not defined upper set "upper=%%~I"
set "upper=%upper:~3%"
echo %upper%
26
задан Drew Noakes 15 January 2009 в 17:24
поделиться

13 ответов

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

public IEnumerator<Expression<T>> GetEnumerator()
{
    if (IsLeaf)
    {
        yield return this;
    }
    else
    {
        foreach (Expression<T> expr in LeftExpression)
        {
            yield return expr;
        }
        foreach (Expression<T> expr in RightExpression)
        {
            yield return expr;
        }
        yield return this;
    }
}

Тогда я могу просто использовать foreach для пересечения выражения. Можно также добавить Свойство для изменения пересекающегося алгоритма по мере необходимости.

12
ответ дан Morten Christiansen 15 October 2019 в 07:01
поделиться

Урожай очень полезен в целом. Именно в рубине среди других языков поддерживают функциональное программирование стиля, таким образом, как он связывается с linq. Это больше наоборот, что linq функционален в стиле, таким образом, это использует урожай.

у меня была проблема, где моя программа использовала много CPU в некоторых фоновых задачах. То, что я действительно хотел, должно было все еще быть в состоянии записать функции как нормальный, так, чтобы я мог легко считать их (т.е. целая поточная обработка по сравнению с основанным на событии аргументом). И все еще будьте в состоянии разбить функции, если они взяли слишком много CPU. Урожай идеально подходит для этого. Я записал , сообщение в блоге об этом и источнике доступно для всех к grok:)

0
ответ дан Anders Rune Jensen 15 October 2019 в 07:01
поделиться

Я использовал урожай в вещах кода non-linq как это (принимающие функции не живут в том же классе):

public IEnumerable<string> GetData()
{
    foreach(String name in _someInternalDataCollection)
    {
        yield return name;
    }
}

...

public void DoSomething()
{
    foreach(String value in GetData())
    {
        //... Do something with value that doesn't modify _someInternalDataCollection
    }
}

необходимо бояться непреднамеренно изменять набор, которого GetData () функция выполняет итерации, хотя, или это выдаст исключение.

0
ответ дан Anton 15 October 2019 в 07:01
поделиться

Обратите внимание, что урожай позволяет Вам делать вещи "ленивым" способом. Ленивым я подразумеваю, что оценка следующего элемента в IEnumberable не сделана, пока элемент на самом деле не требуют. Это позволяет Вам питание сделать несколько разных вещей. Каждый - это, Вы могли привести к бесконечно длинному списку без потребности на самом деле сделать бесконечные вычисления. Во-вторых, Вы могли возвратить перечисление функциональных приложений. Функции были бы только применены, когда Вы выполняете итерации через список.

1
ответ дан Logicalmind 15 October 2019 в 07:01
поделиться

Урожай полезен, потому что он сохраняет Вас пространство. Большая часть оптимизации в программировании делает компромисс между пространством (диск, память, объединяясь в сеть) и обработкой. Урожай как конструкция программирования позволяет Вам много раз выполнять итерации по набору в последовательности, не будучи нужен в отдельной копии набора для каждого повторения.

рассматривают этот пример:

static IEnumerable<Person> GetAllPeople()
{
    return new List<Person>()
    {
        new Person() { Name = "George", Surname = "Bush", City = "Washington" },
        new Person() { Name = "Abraham", Surname = "Lincoln", City = "Washington" },
        new Person() { Name = "Joe", Surname = "Average", City = "New York" }
    };
}

static IEnumerable<Person> GetPeopleFrom(this IEnumerable<Person> people,  string where)
{
    foreach (var person in people)
    {
        if (person.City == where) yield return person;
    }
    yield break;
}

static IEnumerable<Person> GetPeopleWithInitial(this IEnumerable<Person> people, string initial)
{
    foreach (var person in people)
    {
        if (person.Name.StartsWith(initial)) yield return person;
    }
    yield break;
}

static void Main(string[] args)
{
    var people = GetAllPeople();
    foreach (var p in people.GetPeopleFrom("Washington"))
    {
        // do something with washingtonites
    }

    foreach (var p in people.GetPeopleWithInitial("G"))
    {
        // do something with people with initial G
    }

    foreach (var p in people.GetPeopleWithInitial("P").GetPeopleFrom("New York"))
    {
        // etc
    }
}

(Очевидно, Вы не обязаны использовать урожай с дополнительными методами, он просто создает мощную парадигму для размышления о данных.)

, Как Вы видите, если у Вас есть много этих методов "фильтра" (но это может быть любой вид метода, который делает некоторую работу над списком людей) можно объединить многих в цепочку из них вместе, не требуя дополнительного пространства памяти для каждого шага. Это - один способ повысить язык программирования (C#) для выражения решений лучше.

первый побочный эффект урожая состоит в том, что он задерживает выполнение логики фильтрации, пока Вы на самом деле не требуете его. Если Вы поэтому создаете переменную типа IEnumerable<> (с урожаями), но никогда не выполняют итерации через него, Вы никогда не выполняете логику или занимаете место, которое является мощной и бесплатной оптимизацией.

другой побочный эффект состоит в том, что урожай воздействует на самый низкий общий интерфейс набора (IEnumerable<>), который включает создание подобного библиотеке кода с широкой применимостью.

1
ответ дан Pieter Breed 15 October 2019 в 07:01
поделиться

Personnally, я не нашел, что использую урожай в своем нормальном ежедневном программировании. Однако я недавно начал играть с образцами Studio Робототехники и нашел, что урожай используется экстенсивно там, таким образом, я также вижу, что он используется в сочетании с CCR (Параллелизм и Время выполнения Координации), где Вы имеете асинхронный и проблемы параллелизма.

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

1
ответ дан Harrison 15 October 2019 в 07:01
поделиться

Каждый раз, когда Ваша функция возвращает IEnumerable, необходимо использовать "получение". Не в.Net> 3.0 только.

пример.Net 2.0:

  public static class FuncUtils
  {
      public delegate T Func<T>();
      public delegate T Func<A0, T>(A0 arg0);
      public delegate T Func<A0, A1, T>(A0 arg0, A1 arg1);
      ... 

      public static IEnumerable<T> Filter<T>(IEnumerable<T> e, Func<T, bool> filterFunc)
      {
          foreach (T el in e)
              if (filterFunc(el)) 
                  yield return el;
      }


      public static IEnumerable<R> Map<T, R>(IEnumerable<T> e, Func<T, R> mapFunc)
      {
          foreach (T el in e) 
              yield return mapFunc(el);
      }
        ...
2
ответ дан macropas 15 October 2019 в 07:01
поделиться

yield был разработан для C#2 (перед Linq в C#3).

Мы использовали его в большой степени в веб-приложении крупного предприятия C#2 при контакте с доступом к данным и в большой степени повторили вычисления.

Наборы являются большими любое время, у Вас есть несколько элементов, которые Вы собираетесь поразить многократно.

Однако в большом количестве сценариев доступа к данным у Вас есть большие количества элементов, которые необходимо не обязательно передать по кругу в большом большом наборе.

Это по существу, что эти SqlDataReader делает - это - вперед только пользовательский перечислитель.

, Чему yield позволяет, Вы сделать быстро, и с минимальным кодом пишут Ваши собственные перечислители.

Все yield делает мог быть сделан в C#1 - он просто взял стопки кода, чтобы сделать это.

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

8
ответ дан Keith 15 October 2019 в 07:01
поделиться

В предыдущей компании я писал циклы как это:

for (DateTime date = schedule.StartDate; date <= schedule.EndDate; 
     date = date.AddDays(1))

С очень простым блоком итератора, я смог изменить это на:

foreach (DateTime date in schedule.DateRange)

Это сделало код намного легче читать, IMO.

11
ответ дан Nawaz 15 October 2019 в 07:01
поделиться

я действительно понимаю его полноценность в linq, но я чувствую, что только linq команда пишет такие сложные queriable объекты, что урожай полезен.

Урожай был полезен, как только он был реализован в.NET 2.0, который был задолго до того, как любой когда-либо думал о LINQ.

, Почему был бы, я пишу эту функцию:

IList<string> LoadStuff() {
  var ret = new List<string>();
  foreach(var x in SomeExternalResource)
    ret.Add(x);
  return ret;
}

, Когда я могу использовать урожай и сэкономить усилия и сложность создания временного списка ни на каком серьезном основании:

IEnumerable<string> LoadStuff() {
  foreach(var x in SomeExternalResource)
    yield return x;
}

Это может также иметь огромные преимущества производительности. Если Ваш код только, окажется, будет использовать первые 5 элементов набора, то использование урожая будет часто избегать усилия по загрузке чего-либо мимо той точки. Если Вы создаете набор, тогда возвращают его, Вы тратите впустую тонну вещей загрузки времени и пространства, в которых Вы никогда не будете нуждаться.

я мог продолжить и на....

19
ответ дан Orion Edwards 15 October 2019 в 07:01
поделиться

Обратите внимание, что с урожаем, Вы выполняете итерации по набору однажды, но когда Вы создадите список, Вы будете выполнять итерации по нему дважды.

Берут, например, итератор фильтра:

IEnumerator<T>  Filter(this IEnumerator<T> coll, Func<T, bool> func)
{
     foreach(T t in coll)
        if (func(t))  yield return t;
}

Теперь, можно объединить это в цепочку:

 MyColl.Filter(x=> x.id > 100).Filter(x => x.val < 200).Filter (etc)

Вы метод создал бы (и бросил бы), три списка. Мой метод выполняет итерации по нему только однажды.

кроме того, при возврате набора Вы вызываете конкретную реализацию на Вас пользователи. Итератор более универсален.

27
ответ дан James Curran 15 October 2019 в 07:01
поделиться

Я не уверен в реализации C# урожая (), но на динамических языках, это намного более эффективно, чем создание целого набора. на многих случаях это облегчает работать с наборами данных, намного больше, чем RAM.

2
ответ дан Javier 15 October 2019 в 07:01
поделиться

Я большой поклонник Yield в C#. Особенно это касается больших доморощенных фреймворков, где часто методы или свойства возвращают List, который является подмножеством другого IEnumerable. Преимущества, которые я вижу:

  • возвращаемое значение метода, использующего yield неизменяемо
  • вы только итерацируете по списку один раз
  • это переменная позднего или ленивого исполнения, что означает, что код для возврата значений не выполняется до тех пор, пока в нем нет необходимости (хотя это может вас укусить, если вы не знаете, что делаете)
  • из списка исходных текстов, вам не нужно звонить, чтобы получить другой IEnumerable, вы просто делаете итерации над IEnumeable снова
  • многие другие

Еще одно ОГРОМНОЕ преимущество yield в том, что ваш метод потенциально может вернуть миллионы значений. Настолько много, что есть вероятность того, что у вас закончится память, просто построив список еще до того, как метод сможет его вернуть. С помощью yield метод может просто создавать и возвращать миллионы значений, и до тех пор, пока вызывающий метод не будет хранить каждое значение. Поэтому он хорош для крупномасштабных операций обработки данных/агрегации

.
2
ответ дан 28 November 2019 в 06:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: