计算相等的元素

如何解决计算相等的元素

我有这个清单:

(2 2 2 2 3 4 4 5 5 5 6 7 7 7 8 8)

并想返回重复次数。结果应该是这样的:

(4 1 2 3 1 3 2)

我尝试了递归方法,但没有成功。我不确定这是正确的方法。
首先我做了一个函数来计算元素相等时的数量:

(defun count-until-dif (alist)
  (1+  (loop for i from 0 to (- (length alist) 2)
      while (equal  (nth i alist) (nth (1+ i) alist))
      sum 1)))

然后是递归函数(不起作用!):

(defun r-count-equal-elem (alist)
  (cond
    ((NULL alist) nil)
    ((NULL (car alist)) nil)
    ((NULL (cadr alist)) nil)
    ((equal (car alist) (cadr alist))
     (cons  (count-until-dif alist) (r-count-equal-elem (cdr alist)))
      )
    (t (cons 1  (r-count-equal-elem (cdr alist)) )
       ) ) )

解决方法

这是您的函数,并带有一些注释:

(defun r-count-equal-elem (alist)
  (cond
    ((NULL alist) nil)
    ;; the two tests below are not necessary in my opinion,;; the fact that the list may contain NIL elements should
    ;; be a separate problem,as a first draft you can avoid it
    ((NULL (car alist)) nil)
    ((NULL (cadr alist)) nil)
    ;; what you should be testing is if the cddr is NULL,this would
    ;; tell you that there is only one remaining element in the list.
     ((equal (car alist) (cadr alist))
     ;; you cons the count with a recursive result computed just 
     ;; one place after the current one,but if you have a repetition of
     ;; N times value V,the recursive count will contain N-1 repetitions
     ;; of V,etc. you have to advance in the list by N for the recursive
     ;; case
     (cons  (count-until-dif alist) (r-count-equal-elem (cdr alist)))
      )
     ;; this looks like a corner case that could be merged 
     ;; with the general case above.
    (t (cons 1 (r-count-equal-elem (cdr alist)) )
       ) ) )

另外,辅助函数有点低效:

(defun count-until-dif (alist)
  ;; each time you call count-until-dif you compute the length
  ;; of the linked list,which needs to traverse the whole list.
  ;; you generally do not need to know the length,you need to know
  ;; if there is a next element or not to guard your iteration.
  (1+  (loop for i from 0 to (- (length alist) 2)
      while (equal  (nth i alist) (nth (1+ i) alist))
      sum 1)))

我建议编写一个如下所示的函数 occur-rec

(defun occur-rec (list last counter result)
  (if (null list)
      ....
      (destructuring-bind (head . tail) list
        (if (equal head last)
            (occur-rec ... ... ... ...)
            (occur-rec ... ... ... ...)))))

该函数最初使用输入列表调用,last 所见值绑定到 nil,当前 counter 设置为零,result 为 { {1}}。

该函数的目的是通过递归调用 nil 将结果的反向构建为 resultoccur-rec 参数表示哪个是最后看到的值,last 是最后一个值的出现次数。

注意:

  • 当你调用 counter 时,它返回你想要返回的反向列表
  • 反转后的第一项将始终为零,因此您需要将其丢弃。
,

一种幼稚的方法可能如下:

(2 2 2 2 3 4 4 5 5 5 6 7 7 7 8 8)

首先,使用返回 (remove-duplicates '(1 2 2 3))

的函数 (1 2 3) 获取唯一数字列表
(2 3 4 5 6 7 8)

然后对于每个数字,计算它们在第一个列表中出现的次数:

(let ((repetitions '()))
  (dolist ((value unique-list))
    (let ((count (count-if (lambda (x)
                             (= x value))
                           initial-list)))
      (push count repetitions))))
,

一种直接的方法是使用 count-if 来计算列表的第一个元素出现的次数,并使用 nthcdr 来减少列表来递归输入列表。这仅适用于元素组合在一起的列表,如 OP 示例输入。

(defun count-reps (xs)
  (if (endp xs)
      '()
      (let ((count (count-if #'(lambda (x) (eql x (car xs))) xs)))
        (cons count (count-reps (nthcdr count xs))))))
CL-USER> (count-reps '(2 2 2 2 3 4 4 5 5 5 6 7 7 7 8 8))
(4 1 2 3 1 3 2)

这是一种不使用 count-if 递归构建计数列表的替代解决方案:

(defun count-reps (xs)
  (if (endp xs)
      '()
      (let ((rest-counts (count-reps (cdr xs))))
        (if (eql (car xs) (cadr xs))
            (cons (1+ (car rest-counts))
                  (cdr rest-counts))
            (cons 1 rest-counts)))))

此处的 rest-counts 表示列表其余部分的计数列表。当列表的第一个元素和列表的第二个元素为eql时,第一个计数递增;否则遇到一个新元素,并且 1 被cons添加到计数列表中。

您发布的解决方案从正确的方向开始,但递归函数 r-count-equal-elem 有点偏离轨道。您不需要使用 null 检查这么多情况,并且没有理由检查 equal 的元素,因为您已经在 count-until-dif 中这样做了。实际上,使用 count-until-dif,您可以通过与上述第一个解决方案非常相似的方式来解决问题:

(defun r-count-equal-elem (alist)
  (if (null alist)
      '()
      (let ((count (count-until-dif alist)))
        (cons count
              (r-count-equal-elem (nthcdr count alist))))))
,

我还会添加带有 reduce 的功能性(ish)变体:

(defun runs (data &key (test #'eql))
  (when data
    (flet ((add-item (res-alist x)
             (if (funcall test x (caar res-alist))
                 (progn (incf (cdar res-alist))
                        res-alist)
                 (cons (cons x 1) res-alist))))
      (nreverse (reduce #'add-item (cdr data)
                        :initial-value (list (cons (car data) 1)))))))

CL-USER> (runs '(2 2 2 2 3 4 4 5 5 5 6 7 7 7 8 8) :test #'=)
;;=> ((2 . 4) (3 . 1) (4 . 2) (5 . 3) (6 . 1) (7 . 3) (8 . 2))

CL-USER> (mapcar #'cdr (runs '(2 2 2 2 3 4 4 5 5 5 6 7 7 7 8 8) :test #'=))
;;=> (4 1 2 3 1 3 2)
,

使用 loop

(defun count-reps (list)
  (loop for count from 1
        for (curr next) on list
        unless (eql curr next)
        collect (shiftf count 0)))

文字相同;在循环中,从 1 设置一个自动递增计数器 COUNT,并选择参数列表的连续子列表的第一个 (CURR) 和第二个元素 (NEXT),忽略列表的其余部分。当第一个 (CURR) 和第二个 (NEXT) 元素不同时(或者因为不同的数字,或者我们在 NEXT 为 nil 的末尾),将 COUNT 的值存储在结果列表中,并将 COUNT 设置为 0。>

使用 mapl 的 lispier 版本,类似于 loop 的“for ... on list”服务列表的连续 cdrs:

(defun count-reps (list &aux (counter 0) (result (list)))
  (mapl (lambda (head)
          (incf counter)
          (unless (eql (first head) (second head))
            (push (shiftf counter 0) result)))
        list)
  (reverse result))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-