Списки списков
Last updated
Last updated
Добавим еще один уровень в иерархию. Если взять колоду карт из первого примера и создать рамку, в которой будет находиться несколько колод, то эта рамка будет представлять собой список колод, а каждая колода — список карт. Это и есть список списков. В качестве аналогичного примера для этого раздела ниже представлен список столбиков монет, каждый из которых содержит список монет.
Фото предоставлено Dori.
Какие запросы доступны в таком списке списков? Это возможность вызова существующих свойств.
Сколько всего типов монет? 2.
Какова ценность типов монет? $0.01 и $0.25.
Какие материалы используются для изготовления монет номиналом 0,25 долл. США? 75 % меди и 25 % никеля.
Какие материалы используются для изготовления цента? 97,5 % цинка и 2,5 % меди.
Какие действия можно выполнять со списком списков? Они приведут к изменению списка списков в зависимости от конкретной операции.
Выбрать один столбик из монет номиналом 1 или 25 центов.
Выбрать одну монету номиналом 1 или 25 центов.
Переупорядочить столбики.
Перемешать столбики.
Для каждой из перечисленных выше операций в Dynamo имеется аналогичный узел. Поскольку мы работаем с абстрактными данными, а не с физическими объектами, необходимо установить набор правил, определяющих порядок перемещения вверх и вниз по иерархии данных.
При работе со списками списков данные располагаются по слоям и имеют сложную структуру, но это дает возможность выполнять ряд уникальных параметрических операций. Остановимся подробнее на основных операциях, оставив другие для последующих занятий.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
В данном разделе необходимо усвоить один базовый принцип: Dynamo рассматривает сами по себе списки как объекты. Эта нисходящая иерархия разработана с учетом объектно-ориентированного программирования. Вместо выбора вложенных элементов с помощью, например, команды List.GetItemAtIndex в Dynamo будет выбран индекс основного списка в структуре данных. Этот элемент, в свою очередь, может быть другим списком. Рассмотрим этот вопрос подробнее на примере изображения ниже.
С помощью узла Code Block было задано два диапазона:
0..2; 0..3;
.Эти диапазоны соединены с узлом Point.ByCoordinates, а в качестве переплетения выбран вариант Cross Product (векторное произведение). При этом создается сетка точек, а в качестве выходных данных возвращается список списков.
Обратите внимание, что узел Watch содержит 3 списка с 4 элементами в каждом.
При использовании функции List.GetItemAtIndex с индексом 0 Dynamo выберет первый список и все его содержимое. Другие программы могут выбрать первый элемент каждого списка в структуре данных, но в Dynamo при работе с данными используется иерархия «сверху вниз».
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Функция Flatten удаляет все уровни в структуре данных. Это удобно, если для выполнения операции не требуется наличие иерархий данных, но имеются определенные риски, так как удаляется информация. В примере ниже показан результат выравнивания списка данных.
Вставьте одну строку кода для определения диапазона в узле Code Block:
-250..-150..#4;
.При вставке блока кода во входные данные x и y узла Point.ByCoordinates в качестве варианта переплетения укажем Cross Product (векторное произведение), чтобы получить сетку точек.
Узел Watch показывает наличие списка списков.
Узел PolyCurve.ByPoints создаст ссылки для каждого списка и построит соответствующую сложную кривую. Обратите внимание, что в области предварительного просмотра Dynamo отобразятся четыре сложные кривые, представляющие каждый ряд сетки.
После вставки функции Flatten перед узлом сложной кривой был создан один список для всех точек. Узел PolyCurve.ByPoints создает ссылку для списка, чтобы создать одну кривую, а так как все точки находятся в одном списке, получается одна зигзагообразная сложная кривая, которая проходит по всему списку точек.
Можно также выровнять изолированные уровни данных. С помощью узла List.Flatten можно указать определенное количество уровней данных, чтобы выполнить выравнивание от верхнего уровня иерархии. Это очень полезный инструмент при работе со сложными структурами данных, которые могут быть не всегда нужны в рабочем процессе. Еще один вариант — использовать узел Flatten в качестве функции в List.Map. Далее мы подробнее обсудим List.Map.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
При параметрическом моделировании бывает необходимо изменить структуру данных в существующем списке. С этой целью можно использовать множество других узлов, из которых Chop — самая базовая версия. С помощью функции Chop можно разделить список на вложенные списки с заданным количеством элементов.
Команда Chop (обрезка) делит списки на основе заданной длины списка. В некотором смысле обрезка обратна выравниванию: вместо упрощения структуры данных она добавляет в нее новые уровни. Это удобный инструмент для геометрических операций, таких как в примере ниже.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Узел List.Map/Combine позволяет применить заданную функцию к списку входных данных, но на один шаг вниз по иерархии. Набор комбинаций аналогичен команде Maps, за исключением наличия нескольких наборов входных данных, соответствующих входным данным заданной функции.
Примечание. Это упражнение было создано в предыдущей версии Dynamo. Большая часть функциональных возможностей List.Map была упразднена с добавлением функции List@Level . Дополнительные сведения см. в разделе List@Level ниже.
В качестве краткого введения рассмотрим узел List.Count из предыдущего раздела.
Узел List.Count подсчитывает все элементы в списке. Мы воспользуемся этим для демонстрации работы List.Map.
Вставьте следующие две строки кода в узел Code Block:
-50..50..#Nx; -50..50..#Ny;
.После ввода этих данных блок кода создаст два набора входных данных для Nx и Ny.
С помощью двух узлов Integer Slider задайте значения Nx и Ny путем их присоединения к Code Block.
Соедините каждую строку блока кода с соответствующими входными данными X и Y узла Point.ByCoordinates. Щелкните узел правой кнопкой мыши, выберите «Lacing» (переплетение), а затем Cross Product (векторное произведение). Будет создана сетка точек. Так как мы определили диапазон от -50 до 50, он охватывает сетку Dynamo по умолчанию.
Созданные точки отображаются в узле Watch. Обратите внимание на структуру данных. Мы создали список списков. Каждый список представляет собой ряд точек сетки.
Вставьте узел List.Count в выходные данные узла Watch из предыдущего шага.
Соедините узел Watch с выходными данными List.Count.
Обратите внимание, что узел List.Count выдает значение 5. Это значение равно переменной Nx, заданной в блоке кода. Почему?
Во-первых, в качестве основного входного параметра для создания списков в узле Point.ByCoordinates используется входной параметр «x». Если Nx равно 5, а Ny — 3, получается список, состоящий из 5 списков, в каждом из которых содержится 3 элемента.
Так как Dynamo рассматривает списки сами по себе как объекты, то узел List.Count применяется к основному списку в иерархии. В результате получается значение 5 (количество списков в главном списке).
С помощью узла List.Map спустимся на один шаг вниз по иерархии и на этом уровне выполним функцию.
Обратите внимание, что узел List.Count не имеет входных данных. Так как узел List.Count используется в качестве функции, он будет применен к каждому отдельному списку на один шаг вниз по иерархии. Пустые входные данные узла List.Count соответствуют входным данным списка в узле List.Map.
Результаты узла List.Count теперь выдают список из 5 элементов, в каждом из которых имеется значение 3. Это соответствует длине каждого вложенного списка.
Примечание. Это упражнение было создано в предыдущей версии Dynamo. Большая часть функциональных возможностей List.Combine была упразднена с добавлением функции List@Level . Дополнительные сведения см. в разделе List@Level ниже.
В этом упражнении узел List.Combine используется, чтобы продемонстрировать, как его с его помощью можно применять функцию к отдельным спискам объектов.
Начните с настройки двух списков точек.
Используйте узел Sequence для создания 10 значений, каждое с увеличением на 10.
Соедините результат с входным параметром «x» узла Point.ByCoordinates. В Dynamo будет создан список точек.
Добавьте второй узел Point.ByCoordinates в рабочее пространство. Используйте тот же выходной параметр Sequence в качестве входного параметра «x», но используйте Interger Slider в качестве входного параметра «y» и задайте для него значение 31 (оно может быть любым, если не перекрывается первым набором точек), чтобы два набора точек не перекрывались друг другом.
Используйте List.Combine, чтобы применить функцию к объектам в 2 отдельных списках. В данном случае это будет простая функция рисования линий.
Добавьте узел List.Combine в рабочее пространство и соедините 2 набора точек в качестве входных данных list0 и list1.
Используйте узел Line.ByStartPointEndPoint в качестве входной функции для узла List.Combine.
После этого 2 набора точек с помощью функции Line.ByStartPointEndPoint архивируются или связываются вместе, и в Dynamo возвращаются 10 строк.
См. упражнение в многомерных списках для просмотра другого примера использования List.Combine.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
В отличие от List.Map функция List@Level позволяет выбрать необходимый уровень списка непосредственно на входном порте узла. Эту функцию можно применять ко всем поступающим входным данным узлов и получать доступ к уровням списков быстрее, чем при использовании других методов. Просто сообщите узлу, какой уровень списка требуется использовать в качестве входных данных, и он сам сделает все необходимое.
В этом упражнении с помощью функции List@Level изолируется определенный уровень данных.
Начнем с простой 3D-сетки точек.
Поскольку сетка создается с диапазоном для X, Y и Z, структура данных будет иметь 3 уровня: список X, список Y и список Z.
Эти уровни расположены на разной высоте (уровнях). Они указаны в нижней части марки предварительного просмотра. Столбцы уровня списка соответствуют данным списка выше, что позволяет быстрее найти нужный уровень.
Уровни списка располагаются в обратном порядке, так что данные самого низкого уровня всегда находятся на высоте L1. Благодаря этому графики будут функционировать запланированным образом, даже если что-то изменится в предыдущем алгоритме.
Чтобы использовать функцию List@Level, нажмите кнопку «>». В меню отобразятся два флажка.
Использовать уровни: этот вариант включает функцию List@Level. Если этот флажок установлен, можно с помощью мыши выбрать уровни списка входных данных, которые будут использованы узлом. С помощью этого меню можно быстро проверить различные конфигурации уровней, щелкая мышью выше или ниже.
Сохранить структуру списков: если установить этот флажок, можно будет сохранить структуру уровней этих входных данных. Иногда данные бывают сознательно разделены по вложенным спискам. Если установить этот флажок, можно сохранить структуру списка неизменной без какой-либо потери информации.
Благодаря этой простой 3D-сетке можно получить доступ к структуре списка и визуализировать ее, переключаясь между уровнями списка. Любая комбинация уровня списка и индекса возвращает собственный набор точек из исходного 3D-набора.
С помощью элемента @L2 в DesignScript можно выбрать только список на уровне 2. Список на уровне 2 с индексом 0 включает в себя только первый набор точек Y и возвращает только сетку XZ.
Если задать фильтр уровней L1, можно увидеть все содержимое первого уровня списка. Список на уровне 1 с индексом 0 включает в себя все 3D-точки в одноуровневом списке.
В аналогичном случае с L3 будут видны только точки третьего уровня списка. Список на уровне 3 с индексом 0 включает в себя только первый набор точек Z и возвращает только сетку XY.
В аналогичном случае с L4 будут видны только точки третьего уровня списка. Список на уровне 4 с индексом 0 включает в себя только первый набор точек X и возвращает только сетку YZ.
Несмотря на то, что данный конкретный пример можно также создать с помощью List.Map, функция List@Level существенно упрощает взаимодействие и доступ к данным узла. Ниже представлено сравнение методов List.Map и List@Level.
Оба метода предоставляют доступ к одним и тем же точкам, однако List@Level позволяет легко переключаться между слоями данных в одном узле.
Для доступа к сетке точек с помощью List.Map требуется добавить узел List.GetItemAtIndex в дополнение к List.Map. Для каждого нижестоящего уровня списка необходимо использовать дополнительный узел List.Map. В некоторых сложных списках для получения доступа к нужному уровню информации требуется включение в график значительного количества узлов List.Map.
В этом примере узел List.GetItemAtIndex с узлом List.Map возвращает тот же набор точек и ту же структуру списка, что и List.GetItemAtIndex со значением @L3.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Transpose (транспонирование) — это одна из основных функций при работе со списками списков. Как и в электронных таблицах, при транспонировании происходит перестановка столбцов и строк в структуре данных. Продемонстрируем это с помощью следующей базовой матрицы, а в следующем разделе покажем, как с помощью функции транспонирования создавать геометрические взаимосвязи.
Удалите узлы List.Count из предыдущего упражнения и перенесите их на геометрические объекты, чтобы увидеть, как структурированы данные.
Соедините узел PolyCurve.ByPoints с выходными данными узла Watch из узла Point.ByCoordinates.
На выходе отобразятся 5 сложных кривых, которые можно видеть в области предварительного просмотра Dynamo. Узел Dynamo выполняет поиск списка точек (в данном случае — списка списков точек) и создает из них одну сложную кривую. По сути, каждый список в структуре данных преобразован в кривую.
Узел List.Transpose переставляет все элементы со всеми списками в списке списков. Это может показаться сложным, но в Microsoft Excel используется точно такая же логическая схема транспонирования данных: перестановка столбцов со строками в структуре данных.
Обратите внимание на изменение в списках: после транспонирования структура, состоявшая из 5 списков с 3 элементами, изменилась на 3 списка с 5 элементами в каждом.
Кроме того, обратите внимание на изменение в геометрии: использование узла PolyCurve.ByPoints привело к появлению 3 сложных кривых в перпендикулярном направлении к исходным кривым.
Для определения списка в сокращенном языке блока кода используются квадратные скобки ([]). Это гораздо более быстрый и простой способ создания списков, чем с помощью узла List.Create. Узел Code Block подробно рассматривается в разделе Узлы Code Block и DesignScript. На изображении ниже показано, как можно задать список с несколькими выражениями с помощью блока кода.
Для упрощенного выбора определенных элементов, которые требуется извлечь из сложной структуры данных, в сокращенном языке узла Code Block используются квадратные скобки ([]). Узлы Code Block подробно рассматриваются в главе Узлы Code Block и DesignScript. На изображении ниже показано, как запросить список с несколькими типами данных с помощью блока кода.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
В этом упражнении для редактирования поверхности используется логическая схема из предыдущего упражнения. Эту задачу можно решить интуитивным способом, однако при этом потребуется дополнительная навигация по структуре данных. Необходимо определить поверхность путем перемещения контрольной точки.
Начните со строки узлов выше. Создайте базовую поверхность, которая охватывает всю сетку Dynamo по умолчанию.
С помощью узла Code Block вставьте следующие две строки кода и соедините их с входными параметрами u и v узла Surface.PointAtParameter соответственно:
-50..50..#3;
-50..50..#5;
.Убедитесь, что для параметра Lacing (переплетение) узла Surface.PointAtParameter задано значение Cross Product (векторное произведение).
Узел Watch показывает, что имеется список из 3 списков, каждый из которых содержит 5 элементов.
На этом этапе следует запросить центральную точку в созданной сетке. Для этого выберите центральную точку в списке посередине. Логично, не так ли?
Чтобы убедиться в правильности выбора точки, можно щелкнуть элементы узла Watch для проверки правильности выбора элемента.
При помощи узла Code Block создайте базовую строку кода для запроса списка списков:
points[1][2];
С помощью функции Geometry.Translate переместите выбранную точку вверх в направлении оси Z на 20 единиц.
Кроме того, выберите ряд точек посередине с помощью узла List.GetItemAtIndex. Примечание. Как и при выполнении предыдущего шага, можно запросить список с помощью узла Code Block, используя строку
points[1];
.
Итак, мы успешно запросили центральную точку и переместили ее вверх. Теперь необходимо вставить эту перемещенную точку обратно в исходную структуру данных.
Сначала замените элемент списка, который был изолирован при выполнении предыдущего шага.
С помощью узла List.ReplaceItemAtIndex замените центральный элемент с помощью индекса 2 на замещающий элемент, соединенный с перемещенной точкой (Geometry.Translate).
Выходные данные показывают, что перемещенная точка была вставлена в набор входных данных элемента в середине списка.
После изменения списка необходимо вставить его обратно в исходную структуру данных — список списков.
Используя ту же логическую схему, заменим список в середине на измененный список с помощью узла List.ReplaceItemAtIndex.
Обратите внимание, что индекс этих двух узлов определяется узлами Code Block 1 и 2, что соответствует исходному запросу из узла Code Block (points[1][2]).
Если выбрать список с помощью index 1, то структура данных будет выделена в области предварительного просмотра Dynamo. Итак, мы успешно встроили перемещенную точку в исходную структуру данных.
Существует множество способов создания поверхности из этого набора точек. В данном случае необходимо создать поверхность за счет лофтинга кривых.
Создайте узел NurbsCurve.ByPoints и присоедините новую структуру данных для создания трех NURBS-кривых.
Соедините узел Surface.ByLoft с выходными данными из узла NurbsCurve.ByPoints. Получится модифицированная поверхность. Можно изменить исходное значение Z геометрии. Выполните преобразование и посмотрите, как изменится геометрия.