Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Рекурсия, удаление повторных вхождений  
:(
    Опции темы
s1nn
Дата 4.2.2009, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 4.2.2009

Репутация: нет
Всего: нет



Помогите с функцией. 
Функция удаления повторных вхождений элементов в список (на верхнем уровне). 
Код
 
(defun remrep (elem lst) 
    (cond ((null lst) nil) 
            ((equal elem (car lst)) 
              (remrep elem (cdr lst)) 
            ) 
            (t (cons (car lst) 
                     (remrep elem (cdr lst)) 
                ) 
            ) 
    ) 

(defun delrep (lst) 
    (cond ((null lst) nil) 
        (t (progn 
             (setq lst (cons (car lst) (remrep (car lst)(cdr lst)))) 
               (cons (car lst) (delrep (cdr lst))) 
            ) 
        ) 
    ) 

  

Есть список ((a b) d (e) (a b) d) 

при вызове функции delrep получается такая фигня ((a b) d (e))  

Код
 
(delrep '((a b) d (e) (a b) d)) 
> ((a b) d (e))  
   


Эта функция должна удалять только на верхнем уровне, а она удаляет и подсписки. 

При правильной работе должно получиться ((a b) d (e) (a b)). 

PM MAIL   Вверх
VH_
Дата 5.2.2009, 14:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Элементом списка может быть <атом и> список. Так что удаление подсписков как элементов верхнего уровня происходит вполне корректно. Вот если бы в подсписках удалялись элементы, соответствующие элементам верхнего уровня - это было бы (для представленной функции) действительно некузявно.
Есть <немного более> простая версия требующейся функции:
Хювёнен-Сеппянен "Мир Лиспа" т.1
Код

(defun MAKESET (L) ; в оригинале МНОЖЕСТВО
 (cond
  ((null L) nil)
  ((member (car L) (cdr L)) (MAKESET (cdr L)))
  (T (cons (car L) (MAKESET (cdr L))))))


Это сообщение отредактировал(а) VH_ - 5.2.2009, 14:22
PM MAIL   Вверх
VH_
Дата 5.2.2009, 15:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Однако функция (MAKESET) имеет два «недостатка»:
1) в множестве остаются элементы, расположенные ближе к концу исходного списка. Но ведь для множества в математическом смысле это несущественно;
2) функция пользуется неявным свойством применяемой функции (member) сравнивать элементы списка <по крайней мере в CommonLisp> посредством (EQL), то есть определять тождественность символов и равенство чисел (и то однотипных) и НЕ ОПРЕДЕЛЯТЬ одинаковость списков. При изменении поведения (member), например, при сравнении посредством (EQUAL), либо в другом диалекте повторные подсписки на верхнем уровне оставаться не будут.
Код

(defun F (L &optional acc)
 (cond
  ((null L) (reverse acc))
  (T
   (F
    (cdr L)
    (cond
     ((atom (car L))
      (cond
       ((member (car L) acc :test 'equal) acc)
       (T (cons (car L) acc))))
     (T (cons (car L) acc)))))))

PM MAIL   Вверх
adejneka
Дата 5.2.2009, 22:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



Цитата(VH_ @ 5.2.2009,  15:42)
2) функция пользуется неявным свойством применяемой функции (member) сравнивать элементы списка <по крайней мере в CommonLisp> посредством (EQL), то есть определять тождественность символов и равенство чисел (и то однотипных) и НЕ ОПРЕДЕЛЯТЬ одинаковость списков.

Еще один недостаток первой версии состоит в том, что в Common Lisp функция EQL определяет ТОЖДЕСТВЕННОСТЬ двух списков, т.е. результатом (let ((x '(a b c))) (makeset (list x 'e x))) будет (E (A B C)), а не ((A B C) E (A B C)).
PM MAIL   Вверх
VH_
Дата 6.2.2009, 00:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



«...функция EQL определяет ТОЖДЕСТВЕННОСТЬ двух списков...»
Позвольте не согласиться с данным утверждением. Речь идет об одинаковости в логическом отношении. В приведенном Вами примере (member) сравнивает посредством (EQL) не списки '(a b c) '(a b c), а символы x и x - а они действительно тождественны. Контрпример (комментарии мои):
Код

XLISP-PLUS version 3.04
Portions Copyright (c) 1988, by David Betz.
Modified by Thomas Almy and others.
> (defun MAKESET (L)
 (cond
  ((null L) nil)
  ((member (car L) (cdr L)) (MAKESET (cdr L))) ; (member) использует (EQL)
  (T (cons (car L) (MAKESET (cdr L))))))
MAKESET
> (let ((x '(a b c)) (y '(a b c))) (makeset (list x 'e y))) ; символы X и Y связаны с физически различными списками
((A B C) E (A B C))
> (setq x '(a b c) y x) (makeset (list x 'e y)) ; символ Y связан с тем же списком, что и символ X
(A B C)
>
(E (A B C)) ; результат
> (setq x '(a b c) y '(a b c)) (makeset (list x 'e y)) ; снова символы X и Y связаны с физически различными списками
(A B C)
>
((A B C) E (A B C)) ; результат

PM MAIL   Вверх
adejneka
Дата 6.2.2009, 06:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



Цитата(VH_ @ 6.2.2009,  00:09)
«...функция EQL определяет ТОЖДЕСТВЕННОСТЬ двух списков...»
Позвольте не согласиться с данным утверждением. Речь идет об одинаковости в логическом отношении. В приведенном Вами примере (member) сравнивает посредством (EQL) не списки '(a b c) '(a b c), а символы x и x - а они действительно тождественны.

Хорошо, возможно, слово "тождественны" действительно неудачно (я имел в виду CLHS-термин "identical"). Но я не согласен с тем, что EQL сравнивает символы, сравниваются именно списки:
Код

> (defun MAKESET (L)
 (cond
  ((null L) nil)
  ((member (car L) (cdr L)) (MAKESET (cdr L))) ; (member)  (EQL)
  (T (cons (car L) (MAKESET (cdr L))))))
MAKESET
> (let* ((x '(a b c))
       (l (list x 'e x)))
  (print l)
  (makeset l))
((A B C) E (A B C))
(E (A B C))

PRINT не показывает никаких X.
Код

(let ((x '(a b c))
       (l (list x 'e (progn (setq x '(u v)) x))))
  (print l)
  (makeset l))

Если бы EQL сравнивал иксы, результат здесь был бы очень странный smile.
PM MAIL   Вверх
VH_
Дата 6.2.2009, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Обратимся к Common Lisp HyperSpec (восклицательные знаки мои - VH.):
Function EQL
Syntax:
eql x y => generalized-boolean
Arguments and Values:
x --- an object.
y --- an object.
generalized-boolean --- a generalized boolean.
Description:
The value of eql is true of two objects, x and y, in the folowing cases:
1. If x and y are eq.
2. If x and y are both numbers(!) of the same type and the same value.
3. If they are both characters(!) that represent the same character.
Otherwise(!) the value of eql is false
If an implementation supports positive and negative zeros as distinct values, then (eql 0.0 -0.0) returns false. Otherwise, when the syntax -0.0 is read it is interpreted as the value 0.0, and so (eql 0.0 -0.0) returns true. 
Examples:
 (eql 'a 'b) =>  false
 (eql 'a 'a) =>  true
 (eql 3 3) =>  true
 (eql 3 3.0) =>  false
 (eql 3.0 3.0) =>  true
 (eql #c(3 -4) #c(3 -4)) =>  true
 (eql #c(3 -4.0) #c(3 -4)) =>  false
 (eql (cons 'a 'b) (cons 'a 'c)) =>  false
 (eql (cons 'a 'b) (cons 'a 'b)) =>  false
 (eql '(a . b) '(a . b)) =>  true OR =>  false
 (progn (setq x (cons 'a 'b)) (eql x x)) =>  true
 (progn (setq x '(a . b)) (eql x x)) =>  true
 (eql #\A #\A) =>  true
 (eql "Foo" "Foo") =>  true OR =>  false
 (eql "Foo" (copy-seq "Foo")) =>  false
 (eql "FOO" "foo") =>  false
Normally (eql 1.0s0 1.0d0) is false, under the assumption that 1.0s0 and 1.0d0 are of distinct data types. However, implementations that do not provide four distinct floating-point formats are permitted to «collapse» the four formats into some smaller number of them; in such an implementation (eql 1.0s0 1.0d0) might be true.
Side Effects: None.
Affected By: None.
Exceptional Situations: None.
See Also:
eq, equal, equalp, =, char=
Notes:
eql is the same as eq, except that if the arguments are characters or numbers of the same type then their values are compared. Thus eql tells whether two objects are conceptually the same, whereas eq tells whether two objects are implementationally identical. It is for this reason that eql, not eq, is the default comparison predicate for operators that take sequences as arguments.
eql may not be true of two floats even when they represent the same value. = is used to compare mathematical values.
Two complex numbers are considered to be eql if their real parts are eql and their imaginary parts are eql. For example, (eql #C(4 5) #C(4 5)) is true and (eql #C(4 5) #C(4.0 5.0)) is false. Note that while (eql #C(5.0 0.0) 5.0) is false, (eql #C(5 0) 5) is true. In the case of (eql #C(5.0 0.0) 5.0) the two arguments are of different types, and so cannot satisfy eql. In the case of (eql #C(5 0) 5), #C(5 0) is not a complex number, but is automatically reduced to the integer 5.
PM MAIL   Вверх
adejneka
Дата 6.2.2009, 19:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



Надо было мне привести такой пример:
Код

CL-USER> (let* ((l1 (list 'd (list 'a 'b 'c)))
                (l2 (cons (cadr l1) l1)))
           (print l2)
           (makeset l2))

((A B C) D (A B C)) 
(D (A B C))

Здесь уж точно никакие символы не сравниваются.
PM MAIL   Вверх
VH_
Дата 6.2.2009, 20:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Счас посмотрим. Немного минут можете подождать? Попробую картинку нарисовать - потому что это действительно красиво выглядит.

Это сообщение отредактировал(а) VH_ - 6.2.2009, 20:10
PM MAIL   Вверх
VH_
Дата 6.2.2009, 23:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Картинка к сожалению требует какой-то http:// - присоединяю файл с картинкой (Vingrad ругнулся на bmp - переименуйте файл в LISP.bmp).
В общем, дело в том, что список L2 создается посредством (LET) таким образом, что поле CAR первого элемента содержит указатель на ту же списочную структуру (A B C), что и поле CAR последнего элемента того же списка. Соответственно (member) сравнивает посредством (EQL) объекты (воспользуемся CLHS-style), физически представляющие одно и то же (identical). Потому и результат (makeset) такой.

Присоединённый файл ( Кол-во скачиваний: 7 )
Присоединённый файл  LISP.txt 18,22 Kb
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума LISP
Void
  • Пожалуйста, создавайте темы с содержательными названиями.
  • Lisp — это целое семейство языков. Всегда указывайте в теме используемый диалект (Common Lisp, Scheme и т.д.).
  • Уважаемые учащиеся, здесь всегда рады помочь Вам, но не делать за Вас вашу работу. У вас гораздо больше шансов получить помощь, если Вы приложите усилия и поделитесь с нами проблемами и результатами. В противном случае добро пожаловать в раздел Центр Помощи.
  • Получив ответ на интересующий Вас вопрос, не забудьте пометить его как решённый.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Void.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | LISP | Следующая тема »


 




[ Время генерации скрипта: 0.1271 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.