Тема: Сортировка списка по признаку первого аттрибута

Есть список из 10 пар
((2.10-9 2) (2.10-8 4) (2.10-8 2) (2.10-8 2) (2.10-8 6) (2.10-7 4) (2.10-7 2) (2.10-7 2) (2.10-6 4) (2.10-6 2))
Как сформировать из него 4 подсписка по признаку равенства первого аттрибута, чтобы получилось следующее:
(2.10-9 2); подсписок 1
(2.10-8 4) (2.10-8 2) (2.10-8 2) (2.10-8 6); подсписок 2
(2.10-7 4) (2.10-7 2) (2.10-7 2); подсписок 3
(2.10-6 4) (2.10-6 2); подсписок 4
Порядок элементов в исходном списке может быть любой. Он специально несколько упорядочен для лучшего восприятия.

Re: Сортировка списка по признаку первого аттрибута

> Анатолий Б
Как-то так:

(setq my-dat '(("2.10-9" 2)
           ("2.10-8" 2)
           ("2.10-7" 2)
           ("2.10-8" 6)
           ("2.10-7" 4)
           ("2.10-6" 2)
           ("2.10-7" 2)
           ("2.10-8" 4)
           ("2.10-8" 2)
           ("2.10-6" 4)
          )
)
(defun demo1 (lst)
  (mapcar
    (function
      (lambda (a)
    (vl-remove-if-not (function (lambda (b) (= a (car b)))) lst)
      )
    )
    (pl:list-nodouble (mapcar (function car) lst))
  )
)
(defun demo2 (lst)
  (mapcar
    (function
      (lambda (a)
    (list
      a
      (mapcar
        (function cadr)
        (vl-remove-if-not (function (lambda (b) (= a (car b)))) lst)
      )
    )
      )
    )
    (pl:list-nodouble (mapcar (function car) lst))
  )
)
(defun pl:list-nodouble    (lst / key res)
  (if lst
    (if    (vl-position
      (setq key (car lst))
      (setq res (pl:list-nodouble (cdr lst)))
    )
      res
      (cons key res)
    )
  )
)
(demo1 my-dat)
(demo2 my-dat)

Я бы предпочёл второй вариант, он вернёт список списков, где каждый подсписок предствляет из себя: (<ключ> <список значений>), но это уже дело конкретной задачи.

Re: Сортировка списка по признаку первого аттрибута

Ещё один вариант.

(defun demo3
       (sp / sp e1 e2 sp_new final-sp el el-n)
  (setq    sp (vl-sort sp
            (function (lambda (e1 e2) (= (car e1) (car e2))))
       )
  )
  (while sp
    (setq el (car sp)
      sp_new nil
    )
    (foreach el-n sp
      (if (= (car el-n) (car el))
    (setq sp_new (cons el-n sp_new)
          sp     (vl-remove el-n sp)
    )
      )
    )
    (setq final-sp (cons sp_new final-sp))
  )
  (setq final-sp (reverse final-sp))
)

Re: Сортировка списка по признаку первого аттрибута

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

Re: Сортировка списка по признаку первого аттрибута

Не понятно выражение  (setq res (pl:list-nodouble (cdr lst))) , входящее в состав
(defun pl:list-nodouble  (lst / key res). Может здесь что-то не совсем корректно.

Re: Сортировка списка по признаку первого аттрибута

Кажется и демо4 подоспело...
Возвращает сортированный список.

 (setq my-dat '(("2.10-9" 2)
           ("2.10-8" 2)
           ("2.10-7" 2)
           ("2.10-8" 6)
           ("2.10-7" 4)
           ("2.10-6" 2)
           ("2.10-7" 2)
           ("2.10-8" 4)
           ("2.10-8" 2)
           ("2.10-6" 4)
          )
)
(defun demo4 (my-dat / A2 A3)
  (setq    my-dat (vl-sort my-dat
            (function
              (lambda (a1 a2)
                (< (car a1) (car a2)))))
    a2     (list (car my-dat))
    my-dat (cdr my-dat)
  )
  (foreach a1 my-dat
    (if    (equal (car a1) (caar a2))
      (setq a2 (cons a1 a2))
      (setq a3 (cons a2 a3)
        a2 (list a1)
      )
    )
  )
  (cons a2 a3)
)
; (demo4 my-dat) 

Re: Сортировка списка по признаку первого аттрибута

Анатолий Б пишет:

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

Элементы списка должны быть как - ("2.10-8" 4), а не (2.10-8 4), 2.10-8 для Лиспа переменная с некорректным именем, соответственно и возврат бессмысленный, но nil - не должен быть.

Анатолий Б пишет:

Не понятно выражение (setq res (pl:list-nodouble (cdr lst))) , входящее в состав
(defun pl:list-nodouble (lst / key res). Может здесь что-то не совсем корректно.

Это рекурсия, всё корректно.
Варианты demo3 и demo4 ничем не хуже, выбор - по вкусу.

Re: Сортировка списка по признаку первого аттрибута

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

Re: Сортировка списка по признаку первого аттрибута

Посмотри и этот вариант:

(defun demo-summ_sort (lst / result)
  ; отбор по первому параметру
  (while lst
    (setq result (append result
             (list (vl-remove-if-not
                 '(lambda (a1) (= (caar lst) (car a1)))
                 lst))))
    (setq lst (vl-remove-if '(lambda (a1) (= (caar lst) (car a1))) lst))
    ) ;while
  ; нахождение сумм
  (setq    result
     (mapcar '(lambda (a1) (list (caar a1) (apply '+ (mapcar 'cadr a1))))
         result))
  ; сортировка
  (setq result (vl-sort result '(lambda (a1 a2) (< (car a1) (car a2)))))
  )

Re: Сортировка списка по признаку первого аттрибута

> Анатолий Б
Не совсем понял твои новые мысли...
Напиши, вручную отсортированный список, и я попробую подправить функцию, что-бы все происходило автоматом.

Re: Сортировка списка по признаку первого аттрибута

> Евгений
Я тоже не понял последний пост автора темы. :)

Re: Сортировка списка по признаку первого аттрибута

Исходный список получается извлечением двух аттрибутов из блоков для нескольких блоков.
Например
(setq spis((2.10-9 2) (2.10-8 4) (2.10-8 2) (2.10-8 2) (2.10-8 6) (2.10-7 4) (2.10-7 2) (2.10-7 2) (2.10-6 4) (2.10-6 2)) )
Для данного набора должно после работы программы получиться 4 списка:
1-ый для серии "2.10-6":   ((2.10-6 4) (2.10-6 2))
2-ой для серии "2.10-7":   ((2.10-7 4) (2.10-7 2) (2.10-7 2))
3-ий для серии "2.10-8":  ((2.10-8 4) (2.10-8 2) (2.10-8 2) (2.10-8 6)
4-ый для серии "2.10-9": (2.10-9 2)
Вчера новые мысли спутались. Хотел высказать следующее: после расстановки списка в порядке возрастания серии можно в качестве критерия использовать как равенство, так и неравенство первых элементов пары. Видать перенапрягся что-то.

Re: Сортировка списка по признаку первого аттрибута

Последний вариант с defun demo-summ_sort решает задачу не только сортиовки, но и последующего анализа по суммированию. Это просто песня! То, что надо.
Спасибо!
Но я результаты сортировки вижу только в случае если загружаю программу в режиме Load Seletion, предварительно выделив текс программы.
При попытке вывести результат через  (princ result)  в режиме актиного окна почему-то ответ  выводится nil.
Подскажите где собака зарыта.

Re: Сортировка списка по признаку первого аттрибута

Всё заработало и результаты появились после того, когда убрал в написании defun параметр result после /, то есть осталось (defun demo-summ_sort (lst / )
Объяснить этот эффект не могу, знаний не хватает.
Хотелось бы разобраться с лямбда-функцией. Вижу в примерах, как ее активно используют, а прочувстовать алгоритм пока не удалось.
Спасибо всем, кто откликнулся и предложил свои варианты.
Последний вариант это просто песня!

Re: Сортировка списка по признаку первого аттрибута

> Анатолий Б
А как вы список в программу передаёте?
В функции demo-summ_sort переменная result локальная. И после того как функция отработала result обNILивается.

Re: Сортировка списка по признаку первого аттрибута

Пока сочинял, уже  разобрались...:)

Re: Сортировка списка по признаку первого аттрибута

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

Это временная функция, определяемая "по ходу пъесы". Сразу после отработки она теряется из поля зрения. Определяется аналогично defun.

Re: Сортировка списка по признаку первого аттрибута

result локальная переменая и она вам не нужна в дальнейшем использовании, чтобы не путаться.
просто присваивайте результат своей переменой , например my_result_lst

(setq my_result_lst (demo-summ_sort my-dat))

Re: Сортировка списка по признаку первого аттрибута

> Анатолий Б
Нужно

(princ (demo-summ_sort my-dat))

Re: Сортировка списка по признаку первого аттрибута

> Анатолий Б
Совет.
Создай новую тему и опиши свою задачу в целом(для чего Вы это всё делаете совсем непонятно), может она лучше решается совсем другим путём.
Пообщаемся все над алгоритмом, и может кто-то уже делал подобноё или помозгуем вместе как это лучше зделать(или уже переделать).

Re: Сортировка списка по признаку первого аттрибута

Сегодня вставил подпрограмму сортировки demo-summ_sort в общую программу.
Вылез маленькиий нюанс, который не был учтен в исходных данных. Второй аттрибут с виду целое число. Когда в тестовом наборе из 10 пар он был набран как число, программа отработала четко и выполнила суммирование.
По ходу формирования исходного списка из аттрибутов блока оказалось что второй аттрибут не целое число, а строка и  просуммировать  ее не удается. Как в записи лямбда функции ввести корректировку преобразования данных "atoi" не хватает знаний.

Re: Сортировка списка по признаку первого аттрибута

Добавь в начале функции строку

(setq lst(mapcar '(lambda (a1) (list (car a1)(atof (cadr a1))))my-dat))

Примечание: Я atoi заменил на atof (разница есть)
У меня вопрос, что такое первый атрибут и второй атрибут (просто атрибуты могут в блоке идти в последовательности создавания, а их следует отличать по "Tag" это как имя переменной - это на будущее)
По поводу "demo-summ_sort" - это функция а не процедура (разница есть). Если хочеш можешь просто обрезать функцию (удалить defun и последнюю скобку) и вставить в тело своей программы но незабудь, что result при запуске на исполнение этого блока должен быть nil, а то намучаешся (в ней будут скапливаться данные).
Когда Вы кругом будете использовать глобальные переменные то рано или поздно наколетесь и долго будете искать причину ошибки.
И ещё пару советов:
1) Купите книгу (если купили то прочитайте)
2) Незабывайте, что есть хелпы с примерами

Re: Сортировка списка по признаку первого аттрибута

Спасибо за разъяснение и рекомендации.