# Списки списков

### Списки списков

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

> Фото предоставлено [Dori](https://commons.wikimedia.org/wiki/File:Stack_of_coins_0214.jpg).

### Запрос

Какие **запросы** доступны в таком списке списков? Это возможность вызова существующих свойств.

* Сколько всего типов монет? 2.
* Какова ценность типов монет? $0.01 и $0.25.
* Какие материалы используются для изготовления монет номиналом 0,25 долл. США? 75 % меди и 25 % никеля.
* Какие материалы используются для изготовления цента? 97,5 % цинка и 2,5 % меди.

### Действие

Какие **действия** можно выполнять со списком списков? Они приведут к изменению списка списков в зависимости от конкретной операции.

* Выбрать один столбик из монет номиналом 1 или 25 центов.
* Выбрать одну монету номиналом 1 или 25 центов.
* Переупорядочить столбики.
* Перемешать столбики.

Для каждой из перечисленных выше операций в Dynamo имеется аналогичный узел. Поскольку мы работаем с абстрактными данными, а не с физическими объектами, необходимо установить набор правил, определяющих порядок перемещения вверх и вниз по иерархии данных.

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

## Упражнение

### Нисходящая иерархия

> Скачайте файл с примером, щелкнув ссылку ниже.
>
> Полный список файлов примеров можно найти в приложении.

{% file src="/files/lk7VkVJ3IiDwnfREmaN7" %}

В данном разделе необходимо усвоить один базовый принцип: **Dynamo рассматривает сами по себе списки как объекты**. Эта нисходящая иерархия разработана с учетом объектно-ориентированного программирования. Вместо выбора вложенных элементов с помощью, например, команды **List.GetItemAtIndex** в Dynamo будет выбран индекс основного списка в структуре данных. Этот элемент, в свою очередь, может быть другим списком. Рассмотрим этот вопрос подробнее на примере изображения ниже.

\![Нисходящая](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20top%20down%20hierachy.jpg)

> 1. С помощью узла **Code Block** было задано два диапазона: `0..2; 0..3;`.
> 2. Эти диапазоны соединены с узлом **Point.ByCoordinates**, а в качестве переплетения выбран вариант *Cross Product* (векторное произведение). При этом создается сетка точек, а в качестве выходных данных возвращается список списков.
> 3. Обратите внимание, что узел **Watch** содержит 3 списка с 4 элементами в каждом.
> 4. При использовании функции **List.GetItemAtIndex** с индексом 0 Dynamo выберет первый список и все его содержимое. Другие программы могут выбрать первый элемент каждого списка в структуре данных, но в Dynamo при работе с данными используется иерархия «сверху вниз».

### List.Flatten

> Скачайте файл с примером, щелкнув ссылку ниже.
>
> Полный список файлов примеров можно найти в приложении.

{% file src="/files/obVZ4bmYz5U0Qu24BWS1" %}

Функция Flatten удаляет все уровни в структуре данных. Это удобно, если для выполнения операции не требуется наличие иерархий данных, но имеются определенные риски, так как удаляется информация. В примере ниже показан результат выравнивания списка данных.

\![Упражнение](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20flatten%2001.jpg)

> 1. Вставьте одну строку кода для определения диапазона в узле **Code Block**: `-250..-150..#4;`.
> 2. При вставке *блока кода* во входные данные *x* и *y* узла **Point.ByCoordinates** в качестве варианта переплетения укажем *Cross Product* (векторное произведение), чтобы получить сетку точек.
> 3. Узел **Watch** показывает наличие списка списков.
> 4. Узел **PolyCurve.ByPoints** создаст ссылки для каждого списка и построит соответствующую сложную кривую. Обратите внимание, что в области предварительного просмотра Dynamo отобразятся четыре сложные кривые, представляющие каждый ряд сетки.

\![Упражнение](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20flatten%2002.jpg)

> 1. После вставки функции *Flatten* перед узлом сложной кривой был создан один список для всех точек. Узел **PolyCurve.ByPoints** создает ссылку для списка, чтобы создать одну кривую, а так как все точки находятся в одном списке, получается одна зигзагообразная сложная кривая, которая проходит по всему списку точек.

Можно также выровнять изолированные уровни данных. С помощью узла **List.Flatten** можно указать определенное количество уровней данных, чтобы выполнить выравнивание от верхнего уровня иерархии. Это очень полезный инструмент при работе со сложными структурами данных, которые могут быть не всегда нужны в рабочем процессе. Еще один вариант — использовать узел Flatten в качестве функции в **List.Map**. Далее мы подробнее обсудим **List.Map**.

### Chop

> Скачайте файл с примером, щелкнув ссылку ниже.
>
> Полный список файлов примеров можно найти в приложении.

{% file src="/files/O1pHMYF1HDaYIeTsURec" %}

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

Команда Chop (обрезка) делит списки на основе заданной длины списка. В некотором смысле обрезка обратна выравниванию: вместо упрощения структуры данных она добавляет в нее новые уровни. Это удобный инструмент для геометрических операций, таких как в примере ниже.

\![Упражнение](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20chop.jpg)

### List.Map

> Скачайте файл с примером, щелкнув ссылку ниже.
>
> Полный список файлов примеров можно найти в приложении.

{% file src="/files/bpVs9SAbuU21VPdjrIIc" %}

Узел **List.Map/Combine** позволяет применить заданную функцию к списку входных данных, но на один шаг вниз по иерархии. Набор комбинаций аналогичен команде Maps, за исключением наличия нескольких наборов входных данных, соответствующих входным данным заданной функции.

*Примечание. Это упражнение было создано в предыдущей версии Dynamo. Большая часть функциональных возможностей* **List.Map** *была упразднена с добавлением функции* **List\@Level** *. Дополнительные сведения см. в разделе* [*List@Level*](#lists-of-lists) *ниже.*

В качестве краткого введения рассмотрим узел **List.Count** из предыдущего раздела.

Узел **List.Count** подсчитывает все элементы в списке. Мы воспользуемся этим для демонстрации работы **List.Map**.

!

> 1. Вставьте следующие две строки кода в узел **Code Block**: `-50..50..#Nx; -50..50..#Ny;`.
>
>    После ввода этих данных блок кода создаст два набора входных данных для Nx и Ny.
> 2. С помощью двух узлов *Integer Slider* задайте значения *Nx* и *Ny* путем их присоединения к **Code Block**.
> 3. Соедините каждую строку блока кода с соответствующими входными данными *X* и *Y* узла **Point.ByCoordinates**. Щелкните узел правой кнопкой мыши, выберите «Lacing» (переплетение), а затем *Cross Product* (векторное произведение). Будет создана сетка точек. Так как мы определили диапазон от -50 до 50, он охватывает сетку Dynamo по умолчанию.
> 4. Созданные точки отображаются в узле ***Watch***. Обратите внимание на структуру данных. Мы создали список списков. Каждый список представляет собой ряд точек сетки.

\![Упражнение](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20map%2002.jpg)

> 1. Вставьте узел **List.Count** в выходные данные узла Watch из предыдущего шага.
> 2. Соедините узел **Watch** с выходными данными **List.Count**.

Обратите внимание, что узел List.Count выдает значение 5. Это значение равно переменной Nx, заданной в блоке кода. Почему?

* Во-первых, в качестве основного входного параметра для создания списков в узле **Point.ByCoordinates** используется входной параметр «x». Если Nx равно 5, а Ny — 3, получается список, состоящий из 5 списков, в каждом из которых содержится 3 элемента.
* Так как Dynamo рассматривает списки сами по себе как объекты, то узел **List.Count** применяется к основному списку в иерархии. В результате получается значение 5 (количество списков в главном списке).

\![Упражнение](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20map%2003.jpg)

> 1. С помощью узла **List.Map** спустимся на один шаг вниз по иерархии и на этом уровне выполним *функцию*.
> 2. Обратите внимание, что узел **List.Count** не имеет входных данных. Так как узел **List.Count** используется в качестве функции, он будет применен к каждому отдельному списку на один шаг вниз по иерархии. Пустые входные данные узла **List.Count** соответствуют входным данным списка в узле **List.Map**.
> 3. Результаты узла **List.Count** теперь выдают список из 5 элементов, в каждом из которых имеется значение 3. Это соответствует длине каждого вложенного списка.

### **List.Combine**

*Примечание. Это упражнение было создано в предыдущей версии Dynamo. Большая часть функциональных возможностей List.Combine была упразднена с добавлением функции* **List\@Level** *. Дополнительные сведения см. в разделе* [*List@Level*](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/5_essential_nodes_and_concepts/5-4_designing-with-lists/6-3_lists-of-lists.md#listlevel) *ниже*.

В этом упражнении узел **List.Combine** используется, чтобы продемонстрировать, как его с его помощью можно применять функцию к отдельным спискам объектов.

Начните с настройки двух списков точек.

\![Упражнение](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20combined%2001.jpg)

> 1. Используйте узел **Sequence** для создания 10 значений, каждое с увеличением на 10.
> 2. Соедините результат с входным параметром «x» узла **Point.ByCoordinates**. В Dynamo будет создан список точек.
> 3. Добавьте второй узел **Point.ByCoordinates** в рабочее пространство. Используйте тот же выходной параметр **Sequence** в качестве входного параметра «x», но используйте **Interger Slider** в качестве входного параметра «y» и задайте для него значение 31 (оно может быть любым, если не перекрывается первым набором точек), чтобы два набора точек не перекрывали друг друга.

Используйте **List.Combine**, чтобы применить функцию к объектам в 2 отдельных списках. В данном случае это будет простая функция рисования линий.

\![Упражнение](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20combined%2002.jpg)

> 1. Добавьте узел **List.Combine** в рабочее пространство и соедините 2 набора точек в качестве входных данных list0 и list1.
> 2. Используйте узел **Line.ByStartPointEndPoint** в качестве входной функции для узла **List.Combine**.

После этого 2 набора точек с помощью функции **Line.ByStartPointEndPoint** архивируются или связываются вместе, и в Dynamo возвращаются 10 строк.

{% hint style="info" %}
См. упражнение в многомерных списках для просмотра другого примера использования List.Combine.
{% endhint %}

### List\@Level

> Скачайте файл с примером, щелкнув ссылку ниже.
>
> Полный список файлов примеров можно найти в приложении.

{% file src="/files/Ln0p4lQLlkrGR6tIXkyK" %}

В отличие от **List.Map** функция **List\@Level** позволяет выбрать необходимый уровень списка непосредственно на входном порте узла. Эту функцию можно применять ко всем поступающим входным данным узлов и получать доступ к уровням списков быстрее, чем при использовании других методов. Просто сообщите узлу, какой уровень списка требуется использовать в качестве входных данных, и он сам сделает все необходимое.

В этом упражнении с помощью функции **List\@Level** изолируется определенный уровень данных.

\![List@Level](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20list%20at%20level%2001.jpg)

Начнем с простой 3D-сетки точек.

> 1. Поскольку сетка создается с диапазоном для X, Y и Z, структура данных будет иметь 3 уровня: список X, список Y и список Z.
> 2. Эти уровни расположены на разной высоте (**уровнях**). Они указаны в нижней части марки предварительного просмотра. Столбцы уровня списка соответствуют данным списка выше, что позволяет быстрее найти нужный уровень.
> 3. Уровни списка располагаются в обратном порядке, так что данные самого низкого уровня всегда находятся на высоте L1. Благодаря этому графики будут функционировать запланированным образом, даже если что-то изменится в предыдущем алгоритме.

\![List@Level](https://github.com/DynamoDS/DynamoPrimerNew/blob/master-rus/.gitbook/assets/lists%20of%20lists%20-%20list%20at%20level%2002.jpg)

> 1. Чтобы использовать функцию **List\@Level**, нажмите кнопку «>». В меню отобразятся два флажка.
> 2. **Использовать уровни**: этот вариант включает функцию **List\@Level**. Если этот флажок установлен, можно с помощью мыши выбрать уровни списка входных данных, которые будут использованы узлом. С помощью этого меню можно быстро проверить различные конфигурации уровней, щелкая мышью выше или ниже.
> 3. *Сохранить структуру списков*: если установить этот флажок, можно будет сохранить структуру уровней этих входных данных. Иногда данные бывают сознательно разделены по вложенным спискам. Если установить этот флажок, можно сохранить структуру списка неизменной без какой-либо потери информации.

Благодаря этой простой 3D-сетке можно получить доступ к структуре списка и визуализировать ее, переключаясь между уровнями списка. Любая комбинация уровня списка и индекса возвращает собственный набор точек из исходного 3D-набора.

!

> 1. С помощью элемента @L2 в DesignScript можно выбрать только список на уровне 2. Список на уровне 2 с индексом 0 включает в себя только первый набор точек Y и возвращает только сетку XZ.
> 2. Если задать фильтр уровней L1, можно увидеть все содержимое первого уровня списка. Список на уровне 1 с индексом 0 включает в себя все 3D-точки в одноуровневом списке.
> 3. В аналогичном случае с L3 будут видны только точки третьего уровня списка. Список на уровне 3 с индексом 0 включает в себя только первый набор точек Z и возвращает только сетку XY.
> 4. В аналогичном случае с L4 будут видны только точки третьего уровня списка. Список на уровне 4 с индексом 0 включает в себя только первый набор точек X и возвращает только сетку YZ.

Несмотря на то, что данный конкретный пример можно также создать с помощью **List.Map**, функция **List\@Level** существенно упрощает взаимодействие и доступ к данным узла. Ниже представлено сравнение методов **List.Map** и **List\@Level**.

!

> 1. Оба метода предоставляют доступ к одним и тем же точкам, однако **List\@Level** позволяет легко переключаться между слоями данных в одном узле.
> 2. Для доступа к сетке точек с помощью **List.Map** требуется добавить узел **List.GetItemAtIndex** в дополнение к **List.Map**. Для каждого нижестоящего уровня списка необходимо использовать дополнительный узел **List.Map**. В некоторых сложных списках для получения доступа к нужному уровню информации требуется включение в график значительного количества узлов **List.Map**.
> 3. В этом примере узел **List.GetItemAtIndex** с узлом **List.Map** возвращает тот же набор точек и ту же структуру списка, что и **List.GetItemAtIndex** со значением @L3.

### Transpose

> Скачайте файл с примером, щелкнув ссылку ниже.
>
> Полный список файлов примеров можно найти в приложении.

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

Удалите узлы **List.Count** из предыдущего упражнения и перенесите их на геометрические объекты, чтобы увидеть, как структурированы данные.

!

> 1. Соедините узел **PolyCurve.ByPoints** с выходными данными узла Watch из узла **Point.ByCoordinates**.
> 2. На выходе отобразятся 5 сложных кривых, которые можно видеть в области предварительного просмотра Dynamo. Узел Dynamo выполняет поиск списка точек (в данном случае — списка списков точек) и создает из них одну сложную кривую. По сути, каждый список в структуре данных преобразован в кривую.

!

> 1. Узел **List.Transpose** переставляет все элементы со всеми списками в списке списков. Это может показаться сложным, но в Microsoft Excel используется точно такая же логическая схема транспонирования данных: перестановка столбцов со строками в структуре данных.
> 2. Обратите внимание на изменение в списках: после транспонирования структура, состоявшая из 5 списков с 3 элементами, изменилась на 3 списка с 5 элементами в каждом.
> 3. Кроме того, обратите внимание на изменение в геометрии: использование узла **PolyCurve.ByPoints** привело к появлению 3 сложных кривых в перпендикулярном направлении к исходным кривым.

## Применение Code Block для создания списка

Для определения списка в сокращенном языке блока кода используются квадратные скобки (\[]). Это гораздо более быстрый и простой способ создания списков, чем с помощью узла **List.Create**. Узел **Code Block** подробно рассматривается в разделе [Узлы Code Block и DesignScript](/ru/8_coding_in_dynamo/8-1_code-blocks-and-design-script.md). На изображении ниже показано, как можно задать список с несколькими выражениями с помощью блока кода.

!

#### Запрос блока кода

Для упрощенного выбора определенных элементов, которые требуется извлечь из сложной структуры данных, в сокращенном языке узла **Code Block** используются квадратные скобки (\[]). Узлы **Code Block** подробно рассматриваются в главе [Узлы Code Block и DesignScript](/ru/8_coding_in_dynamo/8-1_code-blocks-and-design-script.md). На изображении ниже показано, как запросить список с несколькими типами данных с помощью блока кода.

!

## Упражнение «Запрос и вставка данных»

> Скачайте файл с примером, щелкнув ссылку ниже.
>
> Полный список файлов примеров можно найти в приложении.

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

Начните со строки узлов выше. Создайте базовую поверхность, которая охватывает всю сетку Dynamo по умолчанию.

!

> 1. С помощью узла **Code Block** вставьте следующие две строки кода и соедините их с входными параметрами *u* и *v* узла **Surface.PointAtParameter** соответственно: `-50..50..#3;` `-50..50..#5;`.
> 2. Убедитесь, что для параметра Lacing (переплетение) узла **Surface.PointAtParameter** задано значение *Cross Product* (векторное произведение).
> 3. Узел **Watch** показывает, что имеется список из 3 списков, каждый из которых содержит 5 элементов.

На этом этапе следует запросить центральную точку в созданной сетке. Для этого выберите центральную точку в списке посередине. Логично, не так ли?

!

> 1. Чтобы убедиться в правильности выбора точки, можно щелкнуть элементы узла Watch для проверки правильности выбора элемента.
> 2. При помощи узла **Code Block** создайте базовую строку кода для запроса списка списков:\
>    `points[1][2];`
> 3. С помощью функции **Geometry.Translate** переместите выбранную точку вверх в направлении оси *Z* на *20* единиц.

!

> 1. Кроме того, выберите ряд точек посередине с помощью узла **List.GetItemAtIndex**. Примечание. Как и при выполнении предыдущего шага, можно запросить список с помощью узла **Code Block**, используя строку `points[1];`.

Итак, мы успешно запросили центральную точку и переместили ее вверх. Теперь необходимо вставить эту перемещенную точку обратно в исходную структуру данных.

!

> 1. Сначала замените элемент списка, который был изолирован при выполнении предыдущего шага.
> 2. С помощью узла **List.ReplaceItemAtIndex** замените центральный элемент с помощью индекса *2* на замещающий элемент, соединенный с перемещенной точкой (**Geometry.Translate**).
> 3. Выходные данные показывают, что перемещенная точка была вставлена в набор входных данных элемента в середине списка.

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

!

> 1. Используя ту же логическую схему, заменим список в середине на измененный список с помощью узла **List.ReplaceItemAtIndex**.
> 2. Обратите внимание, что индекс этих двух узлов определяется узлами **Code Block**\_\_ 1 и 2, что соответствует исходному запросу из узла **Code Block** (*points\[1]\[2]*).
> 3. Если выбрать список с помощью *index 1*, то структура данных будет выделена в области предварительного просмотра Dynamo. Итак, мы успешно встроили перемещенную точку в исходную структуру данных.

Существует множество способов создания поверхности из этого набора точек. В данном случае необходимо создать поверхность за счет лофтинга кривых.

!

> 1. Создайте узел **NurbsCurve.ByPoints** и присоедините новую структуру данных для создания трех NURBS-кривых.

!

> 1. Соедините узел **Surface.ByLoft** с выходными данными из узла **NurbsCurve.ByPoints**. Получится модифицированная поверхность. Можно изменить исходное значение *Z* геометрии. Выполните преобразование и посмотрите, как изменится геометрия.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://primer2.dynamobim.org/ru/5_essential_nodes_and_concepts/5-4_designing-with-lists/3-lists-of-lists.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
