热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从序列中删除所有重复元素

如何解决《从序列中删除所有重复元素》经验,为你挑选了2个好方法。

Common Lisp序列函数remove-duplicates在每个多重性后面都保留一个元素。以下类似功能的目标remove-equals是删除所有重复项。

但是,我想使用内置函数remove-if(而不是迭代)和SBCL的哈希表功能用于:test函数,以将时间复杂度保持在O(n)。迫在眉睫的问题是SBCL相等性测试需要是全局的,但是该测试还需要依赖于的key参数remove-equals。可以满足两个要求吗?

(defun remove-equals (sequence &key (test #'eql) (start 0) end (key #'identity))
  "Removes all repetitive sequence elements based on equality test."
  #.(defun equality-test (x y)
      (funcall test (funcall key x) (funcall key y)))
  #.(sb-ext:define-hash-table-test equality-test sxhash)
  (let ((ht (make-hash-table :test #'equality-test)))
    (iterate (for elt in-sequence (subseq sequence start end))
             (incf (gethash (funcall key elt) ht 0)))
    (remove-if (lambda (elt)
                 (/= 1 (gethash elt ht)))
               sequence :start start :end end :key key)))

Sylwester.. 6

第三个参数将define-hash-table-test测试与哈希函数相关联。使用会sxhash破坏目的,因为应该针对test功能进行调整。(equal x y)暗示(= (sxhash x) (sxhash))。因此,第二参数应该是一个函数test-hash,使得(funcall test x y)暗示(= (test-hash x) (test-hash y))。仅具有测试功能是不可能做到这一点的。最好通过记录它需要散列支持来规避整个过程:

(defun remove-duplicated (sequence &key (test #'eql) (start 0) end (key #'identity))
  "Removes all repetitive sequence elements based on equality test.
   equalily tests other than eq, eql, equal and equalp requires you
   add it to be allowed in a hash table eg. sb-ext:define-hash-table-test in SBCL"

  (let ((ht (make-hash-table :test test)))
    (iterate (for elt in-sequence (subseq sequence start end))
             (incf (gethash (funcall key elt) ht 0)))
    (remove-if (lambda (elt)
                 (/= 1 (gethash elt ht)))
               sequence :start start :end end :key key)))

现在,如果用户需要自定义测试,则需要自己进行:

(defun car-equals (a b)
  (equal (car a) (car b)))

(defun car-equals-hash (p)
  (sxhash (car p)))

(sb-ext:define-hash-table-test car-equals car-equals-hash)

(car-equals '(1 2 3 4) '(1 3 5 7)) ; ==> t
(defparameter *ht* (make-hash-table :test 'car-equals))
(setf (gethash '(1 2 3 4) *ht*) 'found)
(gethash '(1 3 5 7) *ht*) ; ==> found

(remove-duplicated '((5 0 1 2) (5 1 2 3) (5 1 3 2) (5 2 3 4)) 
                   :test #'car-equals 
                   :key #'cdr) 
; ==> ((5 0 1 2) (5 2 3 4))


Rainer Joswi.. 5

像这样的带有读取时间计算函数的东西将无法满足您的要求。从您的代码简化:

(defun foo (a b test)
  #.(defun equality-test (x y)
      (funcall test x y))
  (funcall #'equality-test a b))

这是行不通的。

原因1读取时创建的函数无法从周围的代码访问词法变量(此处无法引用test,因为foo在读取过程中不存在带有函数的环境)

test内部的变量equality-test不引用词法变量。未定义/未声明。

原因2:DEFUN评估为符号

阅读并评估读取时间代码后,代码如下所示:

(defun foo (a b test)
   equality-test
   (funcall #'equality-test a b))

好吧,equality-test是一个未绑定的变量。这是运行时错误。

原因3:该功能equality-test可能不存在

如果我们使用文件编译器来编译代码,则该函数equality-test是在读取表单时在编译时环境内创建的,但它不会成为已编译代码的一部分。



1> Sylwester..:

第三个参数将define-hash-table-test测试与哈希函数相关联。使用会sxhash破坏目的,因为应该针对test功能进行调整。(equal x y)暗示(= (sxhash x) (sxhash))。因此,第二参数应该是一个函数test-hash,使得(funcall test x y)暗示(= (test-hash x) (test-hash y))。仅具有测试功能是不可能做到这一点的。最好通过记录它需要散列支持来规避整个过程:

(defun remove-duplicated (sequence &key (test #'eql) (start 0) end (key #'identity))
  "Removes all repetitive sequence elements based on equality test.
   equalily tests other than eq, eql, equal and equalp requires you
   add it to be allowed in a hash table eg. sb-ext:define-hash-table-test in SBCL"

  (let ((ht (make-hash-table :test test)))
    (iterate (for elt in-sequence (subseq sequence start end))
             (incf (gethash (funcall key elt) ht 0)))
    (remove-if (lambda (elt)
                 (/= 1 (gethash elt ht)))
               sequence :start start :end end :key key)))

现在,如果用户需要自定义测试,则需要自己进行:

(defun car-equals (a b)
  (equal (car a) (car b)))

(defun car-equals-hash (p)
  (sxhash (car p)))

(sb-ext:define-hash-table-test car-equals car-equals-hash)

(car-equals '(1 2 3 4) '(1 3 5 7)) ; ==> t
(defparameter *ht* (make-hash-table :test 'car-equals))
(setf (gethash '(1 2 3 4) *ht*) 'found)
(gethash '(1 3 5 7) *ht*) ; ==> found

(remove-duplicated '((5 0 1 2) (5 1 2 3) (5 1 3 2) (5 2 3 4)) 
                   :test #'car-equals 
                   :key #'cdr) 
; ==> ((5 0 1 2) (5 2 3 4))



2> Rainer Joswi..:

像这样的带有读取时间计算函数的东西将无法满足您的要求。从您的代码简化:

(defun foo (a b test)
  #.(defun equality-test (x y)
      (funcall test x y))
  (funcall #'equality-test a b))

这是行不通的。

原因1读取时创建的函数无法从周围的代码访问词法变量(此处无法引用test,因为foo在读取过程中不存在带有函数的环境)

test内部的变量equality-test不引用词法变量。未定义/未声明。

原因2:DEFUN评估为符号

阅读并评估读取时间代码后,代码如下所示:

(defun foo (a b test)
   equality-test
   (funcall #'equality-test a b))

好吧,equality-test是一个未绑定的变量。这是运行时错误。

原因3:该功能equality-test可能不存在

如果我们使用文件编译器来编译代码,则该函数equality-test是在读取表单时在编译时环境内创建的,但它不会成为已编译代码的一部分。


推荐阅读
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • 在Java8之前,HashMap和其他基于map的类都是通过链地址法解决冲突,它们使用单向链表来存储相同索引值的元素。在最坏的情况下,这种方式会将HashMap的get方法的性能从O ... [详细]
  • 一、HashMap1.HashMap概述:HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是 ... [详细]
  • 要讨论这些常用的默认初始容量和扩容的原因是:当底层实现涉及到扩容时,容器或重新分配一段更大的连续内存(如果是离散分配则不需要重新分配,离散分配都是插入新元素时动态分配内存),要将容器原来的数据全部复 ... [详细]
  • HashMap和Hashtable的区别主要的区别有三点:线程安全性,同步(synchronization),以及速度。(两者都是无序排放)HashMap几乎可以等价于Hashtable,除了Hash ... [详细]
  • 常用API-Hashtable类及其与HashMap、HashSet的区别转载请表明出处:http:blog.csdn.netu012637501(嵌入式_小J的天空)一、Hashtable&l ... [详细]
  • HashMap及HashTable源码解析HashMap在java和Android经常使用到,之前学过数据结构,理解了它的原理,却很 ... [详细]
  • (2.1.8)Java之集合类:set、list、hashmap、hashtable等和迭代器iterator
    一、容器常见的集合类有这些种:实现Collection接口的:Set、List以及他们的实现类。实现Map接口的:HashMap及其实现类编程爱好者学习,下面我我们通过一个图来整体描述一下:这个图片没 ... [详细]
  • 用户购买商品时if(e.CommandName.ToLower()"buy"){判断用户购物车是否为空如果为空则分配 ... [详细]
  • 把某些固定的数据源绑定写到类的方法里,能够使代码更好的适应变化。下面的方法并没有放到类里只是简单的做了示范:protectedvoidPage_Load(objectsen ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
author-avatar
SU大肥婆_545
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有