На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (4) 1 [2] 3 4  все  ( Перейти к последнему сообщению )  
> Spring4D , Функциональное программирование в действии
    До этого мы юзали даные вшитые в код, давайте расширим горизонты :D
    Пример Spring4D с данными из JSON файла, большую часть примера занял код парсинга JSON :D
    ExpandedWrap disabled
      uses
        System.Classes, System.SysUtils, System.Generics.Collections, System.JSON,
        Spring.Collections, Spring.Collections.Enumerable;
       
      type
        TIngredient = record
          IngredientName: string;
          Amount: Single;
          Measurement: string;
          constructor Create(AIngredientName: string; AAmount: Single; AMeasurement: string);
        end;
       
        TRecipe = record
          Id: integer;
          RecipeName: string;
          Ingredients: IList<TIngredient>;
          Steps: IList<string>;
          constructor Create(AId: integer; ARecipeName: string;
            AIngredients: IList<TIngredient>; ASteps: IList<string>);
        end;
       
      { TRecipe }
       
      constructor TRecipe.Create(AId: integer; ARecipeName: string;
        AIngredients: IList<TIngredient>; ASteps: IList<string>);
      begin
        Id:= AId;
        RecipeName:= ARecipeName;
        Ingredients:= AIngredients;
        Steps:= ASteps;
      end;
       
      { TIngredient }
       
      constructor TIngredient.Create(AIngredientName: string; AAmount: Single;
        AMeasurement: string);
      begin
        IngredientName:= AIngredientName;
        Amount:= AAmount;
        Measurement:= AMeasurement;
      end;
       
      function LoadFile(fileName: string): string;
      begin
        var reader:= TStreamReader.Create(fileName);
        try
          Result:= reader.ReadToEnd;
        finally
          reader.Free;
        end;
      end;
       
      function CreateRecipes(json: string): IList<TRecipe>;
      begin
        Result:= TCollections.CreateList<TRecipe>;
        try
          var Root: TJSONValue := TJSONObject.ParseJSONValue(json);
          var vRecipes := Root.GetValue<TJSONArray>('recipes');
          try
            for var vRecipe in vRecipes do
            begin
              var id:= vRecipe.GetValue<integer>('id');
              var name:= vRecipe.GetValue<string>('name');
              var vIngrs := vRecipe.GetValue<TJSONArray>('ingredients');
              var vSteps := vRecipe.GetValue<TJSONArray>('steps');
              var ingredients:= TCollections.CreateList<TIngredient>;
              var steps:= TCollections.CreateList<string>;
       
              for var vIngr in vIngrs do
              begin
                var ingr:= TIngredient.Create(
                  vIngr.GetValue<string>('name'),
                  vIngr.GetValue<Single>('amount'),
                  vIngr.GetValue<string>('measurement')
                );
                ingredients.Add(ingr);
              end;
       
              for var vStep in vSteps do
              begin
                steps.Add(vStep.Value);
              end;
       
              Result.Add(TRecipe.Create(id, name, ingredients, steps));
            end;
          finally
            vRecipes.Free;
          end;
        except
          on E: EJSONException do
            Writeln('Error parsing JSON. Check file format.');
        end;
      end;
       
      begin
        // load json file.
        var s:= LoadFile('recipes.json');
       
        // create recipes list.
        var recipes: IList<TRecipe> := CreateRecipes(s);
       
        // query: recipe name list
        var query := TEnumerable.Select<TRecipe, string>(recipes,
          function (recipe: TRecipe): string
          begin
            Result:= recipe.RecipeName;
          end
        );
       
        // print the results.
        query.ForEach(procedure (const s: string)
        begin
          Writeln(s);
        end);
      end.

    часть recipe.json:
    ExpandedWrap disabled
      {"recipes": [{
        "id": 1,
        "name": "Baked Salmon",
        "ingredients": [{
          "name": "Salmon",
          "amount": 1,
          "measurement": "lb"
        }, {
          "name": "Pine Nuts",
          "amount": 1,
          "measurement": "cup"
        }, {
          "name": "Butter Lettuce",
          "amount": 2,
          "measurement": "cups"
        }, {
          "name": "Yellow Squash",
          "amount": 1,
          "measurement": "med"
        }, {
          "name": "Olive Oil",
          "amount": 0.5,
          "measurement": "cup"
        }, {
          "name": "Garlic",
          "amount": 3,
          "measurement": "cloves"
        }],
        "steps": [
          "Preheat the oven to 350 degrees",
          "Spread the olive oil around a glass baking dish.",
          "Add the salmon, garlic, and pine nuts to the dish.",
          "Bake for 15 minutes.",
          "Add the yellow squash and put back in the oven for 30 minutes.",
          "Remove from oven and let cool for 15 minutes. Add the lettuce and serve."
        ]
      }, {
        "id": 2,
        "name": "Fish Tacos",
        "ingredients": [{
          "name": "Whitefish",
          "amount": 1,
          "measurement": "lb"
        }, {
          "name": "Cheese",
          "amount": 1,
          "measurement": "cup"
        }, {
          "name": "Iceberg Lettuce",
          "amount": 2,
          "measurement": "cups"
        }, {
          "name": "Tomatoes",
          "amount": 2,
          "measurement": "large"
        }, {
          "name": "Tortillas",
          "amount": 3,
          "measurement": "med"
        }],
        "steps": [
          "Cook the fish on the grill until hot.",
          "Place the fish on the 3 tortillas.",
          "Top them with lettuce, tomatoes, and cheese."
        ]
      }, {
        "id": 3,
        "name": "Checken Noodle Soup",
        "ingredients": [{
          "name": "Extra-virgin olive oil",
          "amount": 2,
          "measurement": "tablespoons"
        }, {
          "name": "Yello Onion",
          "amount": 1,
          "measurement": ""
        }, {
          "name": "Carrots",
          "amount": 2,
          "measurement": "meduim"
        }, {
          "name": "Celery",
          "amount": 2,
          "measurement": "stalks"
        }, {
          "name": "Chiken Broth",
          "amount": 8,
          "measurement": "cups"
        }, {
          "name": "Wide Egg Noodles",
          "amount": 1,
          "measurement": "package"
        }, {
          "name": "Cooked Chicken",
          "amount": 1,
          "measurement": "cup"
        }],
        "steps": [
          "Chop and saute onion, carrots, and celery in olive oil until soft.",
          "Add chicken  broth and bring to boil.",
          "Add egg noodles and cook until soft.",
          "Add chicken and simmer."
        ]
      }]}

    Теперь можно вдоволь попрактиковаться в запросах
    Сообщение отредактировано: Cfon -
      Цитата Cfon @
      Задание! :whistle:
      Надо перенести на Delphi. Кто не понел это код JS :D
      ExpandedWrap disabled
        const colors = ["red", "red", "green", "blue", "green"];
        const distinctColors = colors.reduce(
          (distinct, color) =>
            (distinct.indexOf(color) !== -1) ?
              distinct :
              [...distinct, color],
        []);
         
        console.log(distinctColors);
        // ["red", "green", "blue"]

      на самом деле это задание средней сложности.
      ща разбермся почему, смотрите вот что у меня получилось
      ExpandedWrap disabled
        begin
          var colors:= Enumerable<string>.Create(['red', 'red', 'green', 'blue', 'green']);
         
          var distinctColors := colors.Aggregate<IList<string>>(
              TCollections.CreateList<string>,
              function (distinct: IList<string>; color: string): IList<string>
              begin
                Result:= distinct;
                if distinct.IndexOf(color) = -1 then
                begin
                  Result:= TCollections.CreateList<string>(distinct);
                  Result.Add(color);
                end;
              end);
         
          // test
          distinctColors.ForEach(procedure (const s: string)
          begin
            Writeln(s, ', ');
          end);
          // red, green, blue,
        end.

      тут много чего интересного...
      Во первых Aggregate вызывается из объекта colors, который является записью Enumerable. Enumerable предоставлят реализации большого набора методов, в том числе Aggregate<TAccumulate>, реализации которой нет в других структурах данных таких как TList<T> и тд. Поэтому не получится создать например список и обратится к Aggregate<TAccumulate>, его там нет.
      Во-вторых колбэк (анонимка) возвращает копию списка, а не ссылку не исходный список. Тоже происходит и в коде на JS каждый раз возвращается копия массива:
      ExpandedWrap disabled
        [...distinct, color]

      а так в ДелФи, пока не придумали синтаксис по короче :D
      ExpandedWrap disabled
        Result:= TCollections.CreateList<string>(distinct);
        Result.Add(color);

      Зачем это надо? Это создает более безопасный код, следуя одному из принципов функционального программирования - неизменяемости данных, например:
      ExpandedWrap disabled
        begin
          var colors:= Enumerable<string>.Create(['red', 'red', 'green', 'blue', 'green']);
          var colors2:= TCollections.CreateList<string>;
         
          var distinctColors := colors.Aggregate<IList<string>>(
              colors2, //<--- передаем я качестве начального значения colors2
              function (distinct: IList<string>; color: string): IList<string>
              begin
                Result:= distinct;
                if distinct.IndexOf(color) = -1 then
                begin
                  Result.Add(color); //<-- изменяем непосредствено colors2
        //          Result:= TCollections.CreateList<string>(distinct);
        //          Result.Add(color);
                end;
              end);
         
          // меняем список colors2
          colors2.AddRange(['white','black']);
         
          // test
          distinctColors.ForEach(procedure (const s: string)
          begin
            Write(s, ', ');
          end);
          // red, green, blue, white, black,
         
          writeln;
          // test
          colors2.ForEach(procedure (const s: string)
          begin
            Writeln(s);
          end);
          // red, green, blue, white, black,  
        end.

      и что мы видим изменения colors2 повлияли на distinctColors! Их содержимое одинаковое. Это как вы понимаете может в более сложных случаях внести баг, который сложно обнаружить.
      Собствено на этом все. Там еще может возникнуть вопрос почему возвращал IList<string>, а не Enumerable<string>? Ну тут все просто, Enumerable<string> не предоставляет метод IndexOf как в примере JS :D
      Сообщение отредактировано: Cfon -
        Цитата Cfon @
        Ну тут все просто, Enumerable<string> не предоставляет метод IndexOf как в примере JS

        А Contains у него есть
          Цитата jack128 @
          Цитата Cfon @
          Ну тут все просто, Enumerable<string> не предоставляет метод IndexOf как в примере JS

          А Contains у него есть

          О не заметил :D
          Тогда буде даже лучше если вернуть Enumerable<string>, ибо его нельзя никак изменить только копирование:
          ExpandedWrap disabled
            begin
              var colors := Enumerable<string>.Create(['red', 'red', 'green', 'blue', 'green']);
             
              var distinctColors := colors.Aggregate<Enumerable<string>>(
                  TCollections.CreateList<string>,
                  function (distinct: Enumerable<string>; color: string): Enumerable<string>
                  begin
                    Result:= distinct;
                    if not distinct.Contains(color) then
                    begin
            //          Result.Add(color); //<-- никак не изменить Enumerable только копирование
                      Result:= Enumerable<string>.Create(distinct.ToArray + [color]);
                    end;
                  end);
             
              // test
              distinctColors.ForEach(procedure (const s: string)
              begin
                Write(s, ', ');
              end);
              // red, green, blue,
            end;

          Правда мы тут имеем лишнее копирование массива distinct.ToArray, но подругому никак :D
          Возможно Enumerable это дело как то оптимизирует и на самом деле ничего не копируется :D

          Кста у Enumerable есть метод Distint, так шо данный код можно заменить на простой
          ExpandedWrap disabled
            colors:= Enumerable<string>.Create(['red', 'red', 'green', 'blue', 'green']);
            distinctColors:= colors.Distinct;

          но суть примера показать как работает Aggregate<TAccumulate>.

          Далее тут я опять передал в качестве сида (seed) IList<string> :D
          это не опечатка, Enumerable<T> имеет оператор Implicit, который выполняет неявное преобразование типа.
          Сообщение отредактировано: Cfon -
            Возращаемся к посту #16
            Предположим у нас добавился рейтинг рецептов, шо делать? :o
            Фигня если код нормально писан то изи :D зерте шо я делаю :D
            Сначало изменяю TRecipe
            ExpandedWrap disabled
              type
                TRecipe = record
                  Id: integer;
                  RecipeName: string;
                  Ingredients: IList<TIngredient>;
                  Steps: IList<string>;
                  Rating: integer;   //<-- 1
                  constructor Create(AId: integer; ARecipeName: string;
                    AIngredients: IList<TIngredient>; ASteps: IList<string>; ARating: integer);
                                                                           // ^^^ 2
                end;
               
              { TRecipe }
               
              constructor TRecipe.Create(AId: integer; ARecipeName: string;
                AIngredients: IList<TIngredient>; ASteps: IList<string>; ARating: integer);
              begin
                Id:= AId;
                RecipeName:= ARecipeName;
                Ingredients:= AIngredients;
                Steps:= ASteps;
                Rating:= ARating; //<-- 3
              end;

            Далее изменяю метод парсинга JSON CreateRecipes, тут ващ изичи :D
            ExpandedWrap disabled
              .....
                    for var vRecipe in vRecipes do
                    begin
                      var id:= vRecipe.GetValue<integer>('id');
                      var name:= vRecipe.GetValue<string>('name');
                      var vIngrs := vRecipe.GetValue<TJSONArray>('ingredients');
                      var vSteps := vRecipe.GetValue<TJSONArray>('steps');
                      var ingredients:= TCollections.CreateList<TIngredient>;
                      var steps:= TCollections.CreateList<string>;
                      var rating:=  vRecipe.GetValue<integer>('rating'); //<-- 4
               
                      .....
               
                      Result.Add(TRecipe.Create(id, name, ingredients, steps, rating));
                                                                            // ^^^ 5
                    end;
              .....

            тестируем
            ExpandedWrap disabled
              begin
                // load json file.
                var s:= LoadFile('recipes.json');
               
                // create recipes list.
                var recipes: IList<TRecipe> := CreateRecipes(s);
               
                // query: recipe name and rating list
                 var query := TEnumerable.Select<TRecipe, string>(recipes,
                  function (recipe: TRecipe): string
                  begin
                    Result:= Format('Recipe: %s, Rating: %d', [recipe.RecipeName, recipe.Rating]);
                  end
                );
               
                // test
                query.ForEach(procedure (const s: string)
                begin
                  Writeln(s);
                end);
               
              // Recipe: Baked Salmon, Rating: 3
              // Recipe: Fish Tacos, Rating: 5
              // Recipe: Checken Noodle Soup, Rating: 0
              end.

            ВСЕ! :blush:
            Сообщение отредактировано: Cfon -
              Цитата Cfon @
              ExpandedWrap disabled
                const colors = ["red", "red", "green", "blue", "green"];
                const distinctColors = colors.reduce(
                  (distinct, color) =>
                    (distinct.indexOf(color) !== -1) ?
                      distinct :
                      [...distinct, color],
                []);
                 
                console.log(distinctColors);
                // ["red", "green", "blue"]

              Не все йогурты одинаково полезны.
              На мой консервативный взгляд, этот код - отличное доказательство того, как простые операции превращаются в малопонятную хрень из тысяч анонимок, методов, перераспределений и тому подобной муры.
              ExpandedWrap disabled
                const colors = ["red", "red", "green", "blue", "green"];
                const distinctColors = [];
                for (let col of colors)
                  if (distinctColors.indexOf(col) == -1)
                    distinctColors.push(col);


              Добавлено
              То есть это мало того что write-only-код, так он еще и не даст заскучать процессору на массивах чуть больше игрушечных размеров. При N элементах N вызовов функции + M (M - количество уникальных элементов) выделений нового массива с копированием элементов и удалений прежнего. В общем, ответ на вопрос, почему компы имеют 3 ГГц процы и 16 Гб оперативы, а браузер с одной вкладкой по-прежнему тормозит
              Сообщение отредактировано: Fr0sT -
                Задание! :D
                Надо перевести код JS на делфи:
                ExpandedWrap disabled
                  const compose = (...fns) =>
                   (arg) =>
                   fns.reduce(
                   (composed, f) => f(composed),
                   arg
                   )

                - Что это за мура? :lool:
                Это не мура! Это функция высшего порядка композиция! :D
                - Что она делает? :blink:
                Композиция получает список функций, выполняет последовательно над агрументом действия и возвращает результат.
                Сообщение отредактировано: Cfon -
                  Задание оказалось очень сложным :wall:
                  Вот что я осилил, комплятор ругается ошибка типов, я даже не буду приводить ее тут ибо один фиг не понятная :D
                  Все я пас, сами мучайтесь :D
                  Кто решит я буду плюсовать пока я жив :lool:
                  ExpandedWrap disabled
                    type
                      TFunctionalUtils = record
                        class function Compose<T,R>(fns: Enumerable<TFunc<T,R>>): TFunc<T, R>; static;
                      end;
                     
                    { TFunctionalUtils }
                     
                    class function TFunctionalUtils.Compose<T, R>(
                      fns: Enumerable<TFunc<T, R>>): TFunc<T, R>;
                    begin
                      Result:= function (arg: T): R
                      begin
                        Result:= fns.Aggregate<T>(arg,
                          function (composed: T; f: TFunc<T, R>): R
                          begin
                            Result:= f(composed);
                          end);
                      end;
                    end;


                  Добавлено
                  Не я пока тут малеха перекурил и меня осенило чекануть на конкрит дата :D
                  Проверил для целых чисел и что вы думаете работает! Как же все это дело обобщить :wacko:
                  ExpandedWrap disabled
                    class function TFunctionalUtils.Compose(
                      fns: Enumerable<TFunc<integer, integer>>): TFunc<integer, integer>;
                    begin
                      Result:= function (arg: integer): integer
                      begin
                        Result:= fns.Aggregate<integer>(arg,
                          function (composed: integer; f: TFunc<integer, integer>): integer
                          begin
                            Result:= f(composed);
                          end);
                      end;
                    end;
                     
                    function Add5(i: integer): integer;
                    begin
                      Result:= i + 5;
                    end;
                     
                    function Add7(i: integer): integer;
                    begin
                      Result:= i + 7;
                    end;
                     
                    var
                      i: integer;
                      funcs: Enumerable<TFunc<integer,integer>>;
                      func: TFunc<integer,integer>;
                    begin
                      funcs:= Enumerable<TFunc<integer,integer>>.Create([Add5, Add7]);
                      func:=  TFunctionalUtils.Compose(funcs);
                      i:= func(10);
                      Writeln(i);
                    // Output: 22
                    end.


                  Добавлено
                  О обобщил для одного типа :D
                  ExpandedWrap disabled
                    class function TFunctionalUtils.Compose<T>(
                      fns: Enumerable<TFunc<T, T>>): TFunc<T, T>;
                    begin
                      Result:= function (arg: T): T
                      begin
                        Result:= fns.Aggregate<T>(arg,
                          function (composed: T; f: TFunc<T, T>): T
                          begin
                            Result:= f(composed);
                          end);
                      end;
                    end;

                  Как же обобщить для двух разных типов :wacko:
                  Сообщение отредактировано: Cfon -
                    Цитата Cfon @
                    Как же обобщить для двух разных типов

                    конкретно в дельфи - никак. Возможно в плюсах можно (гугли variadic templates) или в соседнем подформуе спрашивай
                      Цитата Cfon @
                      Как же обобщить для двух разных типов :wacko:

                      Все понел, в Spring.Collections.Enumerable нет метода Aggregate с соотвест. сигнатурой там тока для TFunc<T,T>.
                      Да и в моем случае TFunc<T,R> тоже не катит, тут надо не через обобщения, а нужна динамическая типизация как в JS.
                      Так что пока варик TFunc<T,T> покатит.

                      Ну а пока продолжаю выкладывать другую муру :D
                      ExpandedWrap disabled
                        uses
                          System.SysUtils,
                          Spring.Collections;
                         
                        type
                          TPet = record
                            Name: string;
                            Age: integer;
                            constructor Create(AName: string; AAge:integer);
                          end;
                         
                        { TPet }
                         
                        constructor TPet.Create(AName: string; AAge: integer);
                        begin
                          Name:= AName;
                          Age:= AAge;
                        end;
                         
                        begin
                          // Create an array of Pets.
                          var pets:= TCollections.CreateList<TPet>([
                            TPet.Create('Barley', 10),
                            TPet.Create('Boots', 4),
                            TPet.Create('Whiskers', 6)
                          ]);
                         
                          // Determine whether all pet names
                          // in the array start with 'B'.
                          var allStartWithB:= pets.All(function (const pet: TPet): boolean
                            begin
                              Result:= pet.Name.StartsWith('B');
                            end);
                         
                          if allStartWithB then
                            WriteLn('All pet names start with "B".')
                          else
                            WriteLn('Not all pet names start with "B".');
                        end;
                        (* C# code:
                        // Create an array of Pets.
                            Pet[] pets = { new Pet { Name="Barley", Age=10 },
                                           new Pet { Name="Boots", Age=4 },
                                           new Pet { Name="Whiskers", Age=6 } };
                         
                            // Determine whether all pet names
                            // in the array start with 'B'.
                            bool allStartWithB = pets.All(pet =>
                                                              pet.Name.StartsWith("B"));
                         
                            Console.WriteLine(
                                "{0} pet names start with 'B'.",
                                allStartWithB ? "All" : "Not all");
                         
                        // This code produces the following output:
                        //
                        //  Not all pet names start with 'B'.*)
                        end.


                      Добавлено
                      Цитата jack128 @
                      Цитата Cfon @
                      Как же обобщить для двух разных типов

                      конкретно в дельфи - никак. Возможно в плюсах можно (гугли variadic templates) или в соседнем подформуе спрашивай

                      ОК.
                      Сообщение отредактировано: Cfon -
                        А вот пример с IEnumerable<T>.All поинтереснее, тут All заюзан с Where и завершен Select'ом. Сам пример на C# приводится в Linq синтаксисе, так что не сразу понятно как это будет на Делфях:
                        ExpandedWrap disabled
                          begin
                            var People:= TCollections.CreateList<TPerson>([
                              TPerson.Create('Haas',
                                TCollections.CreateList<TPet>([TPet.Create('Barley', 10),
                                                               TPet.Create('Boots', 14),
                                                               TPet.Create('Whiskley', 6)])),
                              TPerson.Create('Fakhouri',
                                TCollections.CreateList<TPet>([TPet.Create('Snowball', 1)])),
                              TPerson.Create('Antebi',
                                TCollections.CreateList<TPet>([TPet.Create('Belle', 8)])),
                              TPerson.Create('Philips',
                                TCollections.CreateList<TPet>([TPet.Create('Sweetie', 2),
                                                               TPet.Create('Rover', 13)]))
                            ]);
                           
                            // Determine which people have pets that are all older than 5.
                            var Persons := People.Where(function (const person: TPerson): Boolean
                              begin
                                Result:= person.Pets.All(function (const pet: TPet): boolean
                                  begin
                                    Result:= pet.Age > 5;
                                  end);
                              end);
                           
                            var Names := TEnumerable.Select<TPerson, string>(Persons,
                              function (person: TPerson): string
                              begin
                                Result:= person.LastName;
                              end
                            );
                           
                            Names.ForEach(procedure (const name: string)
                              begin
                                Writeln(name);
                              end
                            );
                          end.
                          (*List<Person> people = new List<Person>
                              { new Person { LastName = "Haas",
                                             Pets = new Pet[] { new Pet { Name="Barley", Age=10 },
                                                                new Pet { Name="Boots", Age=14 },
                                                                new Pet { Name="Whiskers", Age=6 }}},
                                new Person { LastName = "Fakhouri",
                                             Pets = new Pet[] { new Pet { Name = "Snowball", Age = 1}}},
                                new Person { LastName = "Antebi",
                                             Pets = new Pet[] { new Pet { Name = "Belle", Age = 8} }},
                                new Person { LastName = "Philips",
                                             Pets = new Pet[] { new Pet { Name = "Sweetie", Age = 2},
                                                                new Pet { Name = "Rover", Age = 13}} }
                              };
                           
                          // Determine which people have pets that are all older than 5.
                          IEnumerable<string> names = from person in people
                                                      where person.Pets.All(pet => pet.Age > 5)
                                                      select person.LastName;
                           
                          foreach (string name in names)
                          {
                              Console.WriteLine(name);
                          }
                           
                          /* This code produces the following output:
                           *
                           * Haas
                           * Antebi
                           */*)

                        Я ща буду в основном юзать списки (IList<T>) вместо массивов (Enumerable<T>), по причине непонятных тупяков Делфи :D
                        Каких? У меня на Enumerable часто вылетают каки :D
                        Не буду их описывать, возможно кто юзал тот в курсе :crazy:

                        Да и не путайте IEnumerable<T> c Enumerable<T>.
                        IEnumerable<T> это интерфес, который реализуют различные структуры данных такие как TList<T>, а Enumerable<T> это запись, которая агрегирует этот интерфейс, и реализует его как итератор массива, ну и реализует большой набор методов для работы над этим массивом.

                        Вот что еще интересно, обратите внимание на то что в предикат передается константный параметр (см. All, Where), а вот в анонимке Select'а передается неконстантный параметр, это позволит изменить сам список, если в качестве значения передается объект класса, а не запись, например допустим что TPerson = class, тогда
                        ExpandedWrap disabled
                          var Names := TEnumerable.Select<TPerson, string>(Persons,
                              function (person: TPerson): string
                              begin
                                person.LastName := person.LastName.ToUpper; //<-- меняем значение LastName
                                Result:= person.LastName;
                              end
                            );

                        в итоге имеем измененый список People и Persons, почему в селектах так я беспонятий :D
                        Сообщение отредактировано: Cfon -
                          Обнаружил случайно один интресный момент в работе коллекций Spring4D, суть вот в чем, давайте расмотрим внимательно кусок пред кода
                          ExpandedWrap disabled
                            .....
                              // Determine which people have pets that are all older than 5.
                              var Persons := People.Where(function (const person: TPerson): Boolean
                                begin
                                  Result:= person.Pets.All(function (const pet: TPet): boolean
                                    begin
                                      Result:= pet.Age > 5;
                                    end);
                                end);
                             
                              var Names := TEnumerable.Select<TPerson, string>(Persons,
                                function (person: TPerson): string
                                begin
                                  Result:= person.LastName;
                                end
                              );
                             
                              Names.ForEach(procedure (const name: string)
                                begin
                                  Writeln(name);
                                end
                              );
                            end.

                          тут в анонимке Where явно задан значение 5, как правило в рилкоде там будет переменная, давайте изменим это участок кода
                          ExpandedWrap disabled
                            .....
                              var age:= 5;
                              // Determine which people have pets that are all older than 5.
                              var Persons := People.Where(function (const person: TPerson): Boolean
                                begin
                                  Result:= person.Pets.All(function (const pet: TPet): boolean
                                    begin
                                      Result:= pet.Age > age;
                                    end);
                                end);
                            .....

                          ОК, тут вроде все понятно age замкнулась (захвачена) в анонимке All. Все супер, а теперь давайте изменим значение age где-нибудь ниже по коду:
                          ExpandedWrap disabled
                            .....
                              var age:= 5;
                              // Determine which people have pets that are all older than 5.
                              var Persons := People.Where(function (const person: TPerson): Boolean
                                begin
                                  Result:= person.Pets.All(function (const pet: TPet): boolean
                                    begin
                                      Result:= pet.Age > age;
                                    end);
                                end);
                              
                              age:=10;
                            .....

                          и как вы думаете каков будет результат запроса?
                          Name.ForEach выведет список имен персон, у которых возраст петс нет не > 5, a age > 10! :D
                          Что происходит? :o
                          А происходит так называемое отложенное вычисление!
                          Круто да? :D
                          Т.е реальный запрос будет выполнен только тогда когда будет первое обращение нет даже не к Persons, а к Names! :hang:
                          Сообщение отредактировано: Cfon -
                            Цитата Cfon @
                            Т.е реальный запрос будет выполнен только тогда когда будет первое обращение нет даже не к Persons, а к Names! :hang:

                            На самом деле при обращении к Persons тоже запрос выполниться, просто в селекте нет обращения к Persons, поэтому наш запрос будет выполнен тока в строке Names.ForEach, это я и имел ввиду.

                            - А что делать если нам надо, чтобы значение age было то что определено перед фильтрацией? :huh:
                            Решение простое надо зафиксировать значение age :D
                            - Как?! :blink:
                            Например вот так :D
                            ExpandedWrap disabled
                                var age:= 5;
                                // Determine which people have pets that are all older than 5.
                                var Persons := (function (age: integer): IEnumerable<TPerson>
                                  begin
                                    Result:= People.Where(function (const person: TPerson): Boolean
                                      begin
                                        Result:= person.Pets.All(function (const pet: TPet): boolean
                                          begin
                                            Result:= pet.Age > age;
                                          end);
                                      end);
                                  end)(age);
                                age:= 10; //это уже не влияет на предыдущий результат

                            Ну или определить отдельно функцию и передавать туда age, в принципе тоже что и щас :D

                            А можно еще такую тему зафигачить :D
                            ExpandedWrap disabled
                              var PersonFilter := function (APersons: IEnumerable<TPerson>):
                                    TFunc<integer, IEnumerable<TPerson>>
                                  begin
                                    Result:= function (age: integer): IEnumerable<TPerson>
                                    begin
                                      Result := APersons.Where(function (const person: TPerson): Boolean
                                      begin
                                        Result:= person.Pets.All(function (const pet: TPet): boolean
                                          begin
                                            Result:= pet.Age > age;
                                          end);
                                      end);
                                    end;
                                  end;
                               
                                var FilterByPeople:= PersonFilter(People);
                                var Persons:= FilterByPeople(age);

                            Ну тут я заюзал частичное применение для фиксации первого параметра, в данном случае ссылки на список People.
                            - Зачем нам его фиксировать? :huh:
                            Ну это удобно когда нам надо часто вызывать одну и туже фильтрацию для разных значений age :D
                            В данном случае в принципе можно и два передать не страшно, а если к примеру у нас есть функция где много параметров? Причем все кроме одного остальные не меняются, вот тогда можно заюзать частичное применение и создать функцию с меньшим числом параметром.
                            Сообщение отредактировано: Cfon -
                              Теперь мой пример с рецептами, юзаем IEnumerable<T>.Any, дополнительно юзанул анонимку, ну так для примера :D
                              ExpandedWrap disabled
                                procedure ProcessRecipes;
                                begin
                                  // load json file.
                                  var s:= LoadFile('recipes.json');
                                 
                                  // create recipes list.
                                  var recipes := CreateRecipes(s);
                                ...
                                 
                                  var recipeByIngr:= function (ingredientName: string): IEnumerable<TRecipe>
                                    begin
                                      Result:= recipes.Where(function (const recipe: TRecipe): Boolean
                                      begin
                                        Result:= recipe.Ingredients.Any(function (const ingr: TIngredient): Boolean
                                        begin
                                          Result:= ingr.IngredientName.ToLower.Contains(ingredientName.ToLower);
                                        end);
                                      end);
                                    end;
                                 
                                  // получаем список рецептов, где название
                                  // ингредиента содержит слово 'lettuce'
                                  var query3:= recipeByIngr('lettuce');
                                 
                                  // print the results.
                                  query3.ForEach(procedure (const recipe: TRecipe)
                                  begin
                                    Writeln(recipe.RecipeName);
                                  end);
                                  // Baked Salmon
                                  // Fish Tacos
                                end;

                              Название ингредиента передается как параметр, а recipes через замыкание.
                              Сообщение отредактировано: Cfon -
                                Еще одно замечание по поводу след.кода
                                ExpandedWrap disabled
                                  .....
                                    // Determine which people have pets that are all older than 5.
                                    var Persons := People.Where(function (const person: TPerson): Boolean
                                      begin
                                        Result:= person.Pets.All(function (const pet: TPet): boolean
                                          begin
                                            Result:= pet.Age > 5;
                                          end);
                                      end);
                                   
                                    var Names := TEnumerable.Select<TPerson, string>(Persons,
                                      function (person: TPerson): string
                                      begin
                                        Result:= person.LastName;
                                      end);
                                   
                                    Names.ForEach(procedure (const name: string)
                                    begin
                                      Writeln(name);
                                    end);
                                  end.

                                Тут на самом деле выполнятся только один цикл! Так что нет никаких многоразовых проходов по одному и тому же списку.
                                Where и Select задают операции которые надо произвести, а сам цикл по списку уже выполнит ForEach! Крутяк да? :D
                                - А как быть если результат нужена сохранить без ForEach? :huh:
                                Кол метод ToArray :D
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (4) 1 [2] 3 4  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0729 ]   [ 17 queries used ]   [ Generated: 16.04.24, 23:59 GMT ]