Как при помощи ф-ции mapcar обрабатывать сложные списки?

Автор Тема: Как при помощи ф-ции mapcar обрабатывать сложные списки?  (Прочитано 25221 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Юрий АнаньевАвтор темы

  • ADN Club
  • Сообщений: 21
  • Карма: 1
  • Skype: ananiev-yuriy
Всем привет!

данный пример использования ф-ции mapcar
Код - Auto/Visual Lisp [Выбрать]
  1. (mapcar '(lambda (x)   (+ 10 x))  '(1 2 3))  
           
возвращает список результатов (11 12 13)

но требуется обработать список с более сложной структурой
Код - Auto/Visual Lisp [Выбрать]
  1. (mapcar
  2.            '(lambda (x)   (+ 10 x))
  3.  
  4.             (list
  5.               1 2 3
  6.               (list 4 5 6)
  7.               (list (list 7 8 9) (list 10 11 12))
  8.             )
  9.          )
на выходе получаем
error: bad argument type: numberp: (4 5 6)

Не подскажете каким образом на выходе получить список результатов с такой же структурой как и на входе?
т.е. для данного примера -    (11 12 13 (14 15 16) ((17 18 19) (20 21 22)))
« Последнее редактирование: 02-02-2015, 15:37:37 от Александр Ривилис »

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1116
  • Карма: 173
В принципе для такой обработки практически идеально подойдет рекурсия. Немного погодя попробую нарисовать код, сейчас срочной работы многовато...
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1116
  • Карма: 173
В качестве первой прикидки:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq lst '(1 2 3 (4 5 6) ((7 8 9) (10 11 12))))
  2.  
  3. (mapcar
  4.   (function
  5.     (lambda (x / f)
  6.       (defun f (x1)
  7.         (cond
  8.           ((listp x1)
  9.            (mapcar (function f) x1)
  10.            )
  11.           (t (+ 10 x1))
  12.           ) ;_ end of cond
  13.         ) ;_ end of defun
  14.       (f x)
  15.       ) ;_ end of lambda
  16.     ) ;_ end of function
  17.   lst
  18.   ) ;_ end of mapcar
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Юрий АнаньевАвтор темы

  • ADN Club
  • Сообщений: 21
  • Карма: 1
  • Skype: ananiev-yuriy
Спасибо Алексей!

Все работает!!

Попытался на основе твоего кода создать универсальный mapcar для обработки сложных списков -

Код - Auto/Visual Lisp [Выбрать]
  1.        
  2. (defun $-mapcar (fnc sp)
  3. (mapcar
  4.   (function
  5.     (lambda (x / f)
  6.       (defun f (x1)
  7.         (cond
  8.           ((listp x1)
  9.            (mapcar (function f) x1)
  10.            )
  11.            (t (eval (read (strcat "(" fnc " x1)"))))
  12.           ) ;_ end of cond
  13.         ) ;_ end of defun
  14.       (f x)
  15.       ) ;_ end of lambda
  16.     ) ;_ end of function
  17.   sp
  18.   ) ;_ end of mapcar
  19. ); defun
  20.  
  21.  
  22.  
  23. (defun d (a)  (+ 10 a))
  24.  
  25. (defun c:test ()
  26.   (setq lst '(1 2 3 (4 5 6) ((7 8 9) (10 11 12))))
  27.   (setq res ($-mapcar "d" lst))
  28.   (print res)  
  29. (princ)); defun
  30.  
  31.  
  32. Command: TEST
  33. (11 12 13 (14 15 16) ((17 18 19) (20 21 22)))
« Последнее редактирование: 02-02-2015, 15:38:02 от Александр Ривилис »

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1116
  • Карма: 173
:) Правда, у меня сильные подозрения, что настолько заморачиваться особой необходимости нет: наверняка можно получить исходный список более однородной структурой.
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Можно и без mapcar'ов:
Код - Auto/Visual Lisp [Выбрать]
  1. (defun rec1+ (lst)
  2.   (if lst
  3.      (cons ((if (listp (car lst))
  4.                 rec1+
  5.                 1+) (car lst))
  6.            (rec1+ (cdr lst)))))

Оффлайн Юрий АнаньевАвтор темы

  • ADN Club
  • Сообщений: 21
  • Карма: 1
  • Skype: ananiev-yuriy
И правда можно!
Проверил в AA-2014-eng и AA-2015-eng

Command: (rec1+ '(1 2 3 (4 5 6) ((7 8 9) (10 11 12))))
(2 3 4 (5 6 7) ((8 9 10) (11 12 13)))


Работает!
И код короче.
Спасибо!

Вот только пока не смог добавить в эту функцию второй аргумент, чтобы исходный список обрабатывался не только ф-цией 1+, а любой произвольной, заданной вторым аргументом.







Оффлайн Юрий АнаньевАвтор темы

  • ADN Club
  • Сообщений: 21
  • Карма: 1
  • Skype: ananiev-yuriy
наверняка можно получить исходный список более однородной структурой.
В моем случае структура определяется данными, извлекаемыми из помещения (space или zone) для формирования различных ведомостей и спецификаций архитектурно-строительных чертежей.
Поэтому хочется создать универсальную ф-цию извлечения данных в такой структуре в которая наиболее удобна будет для обработки в дальнейшем...


Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1116
  • Карма: 173
А, может, выгоднее будет создать ассоциативный список по типу
Код - Auto/Visual Lisp [Выбрать]
  1. '(("space" ("Тип помещения" <Перечисление площадей>)
  2.                 ("Тип помещения" <Перечисление площадей>)
  3.                 ...
  4.                  )
  5.  ("zone" ("Тип зоны / группы помещений" <Перечисление площадей>)
  6.           ("Тип зоны / группы помещений" <Перечисление площадей>)
  7.           ...
  8.           )
  9.  )
  10.  
И обрабатывать уже отдельные типы объектов?
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Вот только пока не смог добавить в эту функцию второй аргумент, чтобы исходный список обрабатывался не только ф-цией 1+, а любой произвольной, заданной вторым аргументом.
Ну по "стандартам лиспа" только не вторым аргументом, а первым (второй список):
Код - Auto/Visual Lisp [Выбрать]
  1. (defun map-rec(fn lst)
  2.   ((lambda (frec) (frec lst))
  3.    (lambda (lst)
  4.      (if lst
  5.          (cons ((if (listp (car lst))
  6.                     frec
  7.                     fn) (car lst))
  8.                (frec (cdr lst)))))))

Оффлайн Юрий АнаньевАвтор темы

  • ADN Club
  • Сообщений: 21
  • Карма: 1
  • Skype: ananiev-yuriy
Работает как и хотел!

Код - Auto/Visual Lisp [Выбрать]
  1. (defun d (a)  (+ 10 a))
  2. (setq lst '(1 2 3 (4 5 6) ((7 8 9) (10 11 12))))
  3. (map-rec d lst)
  4. (11 12 13 (14 15 16) ((17 18 19) (20 21 22)))

Спасибо!
« Последнее редактирование: 04-02-2015, 12:12:32 от Алексей Кулик »

Оффлайн Юрий АнаньевАвтор темы

  • ADN Club
  • Сообщений: 21
  • Карма: 1
  • Skype: ananiev-yuriy
А, может, выгоднее будет создать ассоциативный список по типу
Код - Auto/Visual Lisp: [Выделить]
'(("space" ("Тип помещения" <Перечисление площадей>)
                ("Тип помещения" <Перечисление площадей>)
                ...
                 )
 ("zone" ("Тип зоны / группы помещений" <Перечисление площадей>)
          ("Тип зоны / группы помещений" <Перечисление площадей>)
          ...
          )
 )
 
И обрабатывать уже отдельные типы объектов?

У меня немного другой подход -
на первом этапе отбираются объекты нужного типа на нужном слое (или т.п.)
на втором определяется список для извлечения данных в нужной структуре

(
  (набор1 набор2 набор3)
  (набор1 характеристика3)
  (набор1 характеристика12)
  (
     (набор2 характеристика1)
     (набор2 характеристика3)
     (набор3 характеристика1)
  )
  ...
)
далее получаю список значений нужных характеристик при помощи ф-ции #9
далее обработка значений (вычисления, подчеты, упорядочивание, сортировка ) для получения данных вывода в таблицу
далее вставка таблицы




Оффлайн gomer

  • ADN OPEN
  • Сообщений: 4
  • Карма: 2
Если все таки хочется mapcar...
Код - Auto/Visual Lisp [Выбрать]
  1. (defun tree-apply (f lst)
  2.   (mapcar (function (lambda (x)
  3.              (if (listp x)
  4.                (tree-apply f x)
  5.                (apply (function f)
  6.                       (list x)))))
  7.           lst))

Оффлайн Юрий АнаньевАвтор темы

  • ADN Club
  • Сообщений: 21
  • Карма: 1
  • Skype: ananiev-yuriy
Проверил ф-цию tree-apply
все работает

Код - Auto/Visual Lisp [Выбрать]
  1. (defun d (a)  (+ 10 a))
  2. (setq lst '(1 2 3 (4 5 6) ((7 8 9) (10 11 12))))
  3. (tree-apply d lst)
  4. (11 12 13 (14 15 16) ((17 18 19) (20 21 22)))
  5.  

Спасибо за очередной вариант решения!

С лиспом у меня не очень, с точки зрения корректности и рациональности формирования кода.

И я затрудняюсь в определении того какая из представленных рабочих ф-ций лучше.

Поэтому оставляю выбор поста, соответствующего решению темы, за профессионалами в этой области...



Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13886
  • Карма: 1788
  • Рыцарь ObjectARX
  • Skype: rivilis
Юрий! Просто отметьте ту функцию, которой будете пользоваться. А остальным можете просто "плюсануть в карму". :)
Мне кажется так будет справедливо.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение