如何在 Lisp 中一次生成一个列表中元素的所有排列?

2023-11-26

我已经有了生成元素列表的所有排列的代码。然而,我意识到,如果我想操作生成的列表,我需要遍历这个列表。该列表可能会很大,因此维护成本很高。我想知道是否有一种方法可以通过每次调用生成排列,以便我可以检查列表是否与我需要的匹配,如果不匹配,我将生成下一个排列。 (每次该函数都会一次返回一个列表。)

My code:

(defun allPermutations (list) 
  (cond
     ((null list)  nil) 
     ((null (cdr list))  (list list)) 
     (t  (loop for element in list 
               append (mapcar (lambda (l) (cons element l))
                              (allPermutations (remove element list))))))) 

一般原则

假设您有以下内容range功能:

(defun range (start end &optional (step 1))
  (loop for x from start below end by step collect x))

您可以接受另一个参数,一个函数,并为每个元素调用它:

(defun range-generator (callback start end &optional (step 1))
  (loop for x from start below end by step do (funcall callback x)))

这使调用者可以控制迭代过程:

(block root
  (range-generator (lambda (v)
                     (print v)
                     (when (>= v 10)
                       (return-from root)))
                   0 300))


0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10

See RETURN, BLOCK.

排列

如果您想避免分配太多内存,您可以安排代码分配中间数据结构once并在每次调用回调时重用它们。这是一个带注释的示例:

(defun permutations% (list callback)
  (when list
    (let* (;; Size of input list
           (size (length list))

           ;; EMPTY is a sentinel value which is guaranteed to
           ;; never be equal to any element from LIST.
           (empty (gensym "SENTINEL"))

           ;; Working vector containing elements from LIST, or
           ;; EMPTY. This vector is mutated to remember which
           ;; element from the input LIST was already added to the
           ;; permutation.
           (items (make-array size :initial-contents list))

           ;; Working vector containing the current
           ;; permutation. It contains a FILL-POINTER so that we
           ;; can easily call VECTOR-PUSH and VECTOR-POP to
           ;; add/remove elements.
           (permutation (make-array (length items) :fill-pointer 0)))

      ;; Define a local recursive function named POPULATE, which
      ;; accepts a COUNT argument. The count starts at SIZE and
      ;; decreases at each recursive invocation, allowing the
      ;; function to know when it should end.
      (labels ((populate (count)
                 (if (plusp count)
                     ;; Loop over ITEMS by index
                     (dotimes (item-index size)
                       (let ((item (svref items item-index)))
                         ;; We found an ITEM which is not yet
                         ;; present in PERMUTATION.
                         (unless (eq item empty)
                           ;; Push that element
                           (vector-push item permutation)
                           ;; Replace current value in ITEMS by EMPTY
                           (setf (svref items item-index) empty)

                           ;; POPULATE will recursively populate
                           ;; the remaining elements in
                           ;; PERMUTATION and call CALLBACK. Once
                           ;; it is done, it will return here.
                           (populate (1- count))

                           ;; There are other items to process in
                           ;; current loop. Reset the state to how
                           ;; it was before calling POPULATE.

                           ;; Replace the EMPTY value by the
                           ;; original ITEM at current index.
                           (setf (svref items item-index) item)

                           ;; Remove ITEM from PERMUTATION.
                           (vector-pop permutation))))

                     ;; We filled PERMUTATION with SIZE elements.
                     ;; Call CALLBACK with PERMUTATION. Note: the
                     ;; callback function is always given the same
                     ;; vector, but its content changes over
                     ;; time. The value passed to CALLBACK is thus
                     ;; valid only during the time we are
                     ;; executing CALLBACK. If the caller needs to
                     ;; keep a copy of the current permutation, it
                     ;; should COPY-LIST the value.
                     (funcall callback permutation))))

        ;; Initiate recursive function with current SIZE.
        (populate size)))))

该函数接受一个列表和一个回调,这是一个接受一个参数(当前排列)的函数。注意该参数仅在动态范围调用的,因为一旦调用返回,传递给回调的相同数据结构就会被修改。

如上所述,您可以调用任何函数,特别是引用词法环境中其他变量的闭包。这里,匿名 lambda 递增count变量,它允许计算排列的数量,而不将它们存储在列表中并获取列表的大小:

(time
 (let ((count 0))
   (permutations% '(a b c d e f g h i j k) (lambda (p) (incf count)))
   count))
=> 39916800

Evaluation took:
  6.455 seconds of real time
  6.438200 seconds of total run time (6.437584 user, 0.000616 system)
  99.74% CPU
  17,506,444,509 processor cycles
  0 bytes consed

在上述报告中,0 字节消耗表示分配的内存的大致数量(不包括堆栈分配)。 您还可以提供该函数的更安全版本,该函数在将每个排列发送到回调函数之前复制每个排列。

(defun permutations (list callback)
  (permutations% list (lambda (permutation)
                        (funcall callback (coerce permutation 'list)))))

See also

也可以看看威尔·尼斯的回答,它设法用列表处理剩余元素的集合,从而避免了过滤 EMPTY 元素的需要。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Lisp 中一次生成一个列表中元素的所有排列? 的相关文章

  • 计算 List 中相似的相邻项目数

    我试图在列表中找到相似的相邻项目并计算其数量 例如 List
  • for 循环中列表项未更改

    当以下代码没有达到我预期的效果时 我感到震惊 lines list this is line 1 n this is line 2 n this is line 3 n for line in lines list line line st
  • 列表列中的设置操作

    我正在尝试做集合运算在存储在列表列中的向量之间 例如this https stackoverflow com questions 38712196 text file to dataframe with a list column DT l
  • 如何在python中合并具有相同键的嵌套字典

    我有一个这样的数据结构 SNAPSHOT SnapshotVersion 304 SNAPSHOT SnapshotCreationDate 2015 06 21 17 33 41 CafeData CafeVersion 2807 Caf
  • gensym 在 Lisp 中做什么?

    我听到一些同学谈论他们如何使用该功能gensym为此 我问他们它做了什么 甚至在网上查了一下 但我真的无法理解这个函数的作用是什么两者都不为什么或何时最好使用它 特别是 我对它在 Lisp 中的作用更感兴趣 谢谢你们 独特且未被拘禁的符号
  • 检查多个位置的值并仅在源唯一时返回匹配项

    假设我有一个清单Vendors 阿斯达 乐购 Spar 我有一个清单Sources 或者这个类比中的供应商 家乐氏 Kellogg 吉百利 Cadbury 雀巢 Nestle 强生 Johnsons 帮宝适 Pampers Simple 等
  • Python - 如何将列表保存为图像?

    我生成一个常规列表 是否可以将此列表保存为 JPEG 图像或 PNG 或其他格式 以便我可以打开图像并查看它 我目前正在尝试使用 python 成像库 PIL 来解决这个问题 这是可能的解决方案之一 使用以下方法创建一个空图像对象 Imag
  • 在 Python 中使用 .split() 和 .join()

    我目前正在 Treehouse 中学习一些 Python 但我遇到了这个挑战 并且不知道我做错了什么 挑战分为三个部分 如下所示 包含提示和我编写的代码 我好像在第三部分犯了错误 Part 1 我想是时候吃点零食了 幸运的是 我有一串各种各
  • F# 类型提供程序与 Lisp 宏

    我一直在阅读有关 F 3 0 类型提供程序的内容 例如here http msdn microsoft com en us library hh156509 aspx 并且它们似乎基于一种编译时代码生成 在这方面我想知道它们与 Lisp 宏
  • 如何在 R 中创建循环来生成随机样本列表?

    我正在尝试创建一个循环来创建一系列包含随机样本的对象 如下所示 sample lt ceiling runif 9 min 0 max 20 这是圆形制服的示例 但它可以替换为普通 泊松或任何您想要的 因此 我构建了一个循环来自动生成各种生
  • 根据 Mathematica 中的另一个列表值拆分列表

    在 Mathematica 中我有一个点坐标列表 size 50 points Table RandomInteger 0 size RandomInteger 0 size i 1 n 以及这些点所属的聚类索引列表 clusterIndi
  • C# 的快速线程安全随机数生成器

    我需要在多个正在运行的线程中快速生成随机浮点数 我尝试过使用System Random 但它对于我的需求来说太慢了 并且它在多个线程中返回相同的数字 当我在单线程中运行应用程序时 它工作正常 此外 我需要确保生成的数字在 0 到 100 之
  • 如何将 Python 字典序列化为字符串,然后再序列化回字典?

    如何将 Python 字典序列化为字符串 然后再序列化回字典 字典中将包含列表和其他字典 这取决于您想用它做什么 如果您只是想保存它 您应该使用pickle https docs python org 3 library pickle ht
  • 如何在 Python 中连接两个列表?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 如何在 Python 中连接两个列表 Example listone 1 2 3 lis
  • CMake Xcode生成器创建了一个无法构建的项目

    我有一个使用 CMake 构建系统的 C 项目 我使用 MacBook Pro 进行开发 因此当我使用终端时 一切都非常顺利 我可以构建我的项目 然而 今天我发现我可以在使用 CMake 生成器创建相应的项目后使用 Xcode gt cma
  • 如何将列表转换为元组列表?

    我想转换 z z a z z a a z to z 2 a 1 z 2 a 2 z 1 我该怎么做 所以 我需要累积以前的值 它的计数器和元组列表 我已创建记录 record acc previous counter tuples 重新定义
  • NotImplementedError:尚未为未构建的模型子类启用“fit_generator”

    我正在使用以下代码 import tensorflow as tf traindata tf keras preprocessing image ImageDataGenerator rescale 1 255 shear range 0
  • 学习 Lisp 的资源 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • “Iterable 无法转换为 List” - `List` 不是 `Iterable` 的类型吗?

    我打电话给一个getElements返回的方法Iterable
  • Collections.sort(list) 和 list.sort(Comparator) 之间的区别

    有什么理由让我应该选择Collections sort list 方法而不是简单地调用list sort 内部Collections sort只是调用sort的方法List无论如何 上课 令人惊讶的是几乎每个人都告诉我使用Collectio

随机推荐

  • 如何调整图像大小但保持 sk-image 中的像素值?

    我想调整图像大小 我的图像包含特定值 0 1 2 7 9 调整大小后 会引入新值 例如 5 等 我想阻止这种情况发生 我目前正在使用scikit图像调整大小功能 我已经尝试了所有插值标志但无济于事 编辑 一个简单的代码来显示问题 impor
  • 如何使用.Net Core授权AD用户

    我正在尝试使用以下方法停止路线上的请求Authorize注释 但我无法让它与 Active Directory 一起使用 有人已经开始工作了吗 HttpGet Authorize Roles DOMAIN Group A Route GET
  • 从本地文件跨源GET://

    我正在尝试构建一个 html 文件来监视远程站点上的某些内容 具体来说 github com 我希望能够将其保留为平面文件 直接从 JS 向 github 的 API 发出请求 我的思考过程是这样的 Let s use jsonp sinc
  • .NET Core WebAPI依赖注入解析null

    我使用具有依赖注入和多个身份验证模式 http basic 访问密钥 JWT 的 NET Core WebAPI 我注入一些需要一些经过身份验证的用户数据的业务服务 如果用户通过任何身份验证中间件进行身份验证 DI 就可以正常工作 如果用户
  • 如何在不移动 css 中 div 位置的情况下增加悬停时的边框宽度?

    我试图拥有它 以便将鼠标悬停在圆形 div 上会导致粗虚线边框向外辐射 同时将内部区域保持在同一位置 这个想法是给人一种盛开的花朵的印象 到目前为止 我所尝试的一切都导致中心移动以适应边框宽度的增加 有没有办法用纯CSS来实现我想要的 这就
  • Spring Security 与 Spring Boot:将基本身份验证与 JWT 令牌身份验证混合[重复]

    这个问题在这里已经有答案了 我试图让 Spring Security 的基本身份验证与 JWT 令牌身份验证并行工作 但没有成功 我已经为我的 Web 控制台和 JWT 实现了基本身份验证 以保护许多 API 端点的安全 这是我的配置 En
  • 单步索引与两步索引时 Numpy 3D 数组转置

    import numpy as np x np random randn 2 3 4 mask np array 1 0 1 0 dtype np bool y x 0 mask z x 0 mask print y print z pri
  • 异步任务中的 C# 更改标签文本

    以下代码不会更改文本并停止执行任务 private void button1 Click object sender EventArgs e label1 Text Test Task Run gt MyAsyncMethod public
  • 使用不带 url 的 Web 浏览器自动下载文件

    我一直在使用 System Windows Forms WebBrowser 用 C 编写 WebCrawler 我正在尝试从网站下载文件并将其保存在本地计算机上 更重要的是 我希望这是完全自动化的 单击一个调用 JavaScript 函数
  • 从 Mongoose 模型中找到的本机驱动程序不返回光标

    我正在尝试执行本机 MongoDBfind查询通过collection猫鼬的财产Model 我不提供回调 所以我希望 find 返回一个Cursor对象 但它返回undefined反而 根据猫鼬文档 正在使用的驱动程序可以通过访问YourM
  • Cassandra 中的计数器与 Int 列?

    我是卡桑德拉的新手 我不明白在表中使用计数器有什么好处 或者甚至在不同的表中 如果非计数器列不是复合主键的一部分 当我有一些像 x x 这样的语句时 为什么我们不使用 Int 类型的列 使用 int 或 counter 有什么区别 Cass
  • 错误!无法解析模块/操作。这通常表示拼写错误、集合丢失或模块路径不正确

    我的 Ansible 剧本中有一个 Ansible Collections 如下所示 name Create a profile for the user community windows win user profile usernam
  • 通过外部页面链接开通微信公众号

    我找不到任何关于这个问题的参考资料 我希望这里有人知道 我为客户创建了一个 html5 促销页面 该页面位于我的服务器上 我正在通过微信将页面地址分享给客户 他正在将其重新分享给他的朋友 当他们打开页面时 它会在微信应用浏览器中打开 到目前
  • 缩小评级栏大小时出现问题。

    我想减小评级栏的大小 我有一些样式属性可以做到这一点 但它们超出了用户交互的范围 它们只是指示器 所以 请告诉我如何缩小尺寸 提前致谢 如何粘贴给定的代码here 步骤1 您需要自己的评级星星res drawable 步骤 2 输入res
  • 使用 Group By 时出现 SQL 错误:每个 GROUP BY 表达式必须至少包含一列不是外部引用

    在执行我认为最简单的查询之一时 我遇到了此错误 我看到其他人也在这里遇到了问题 我已经浏览了我见过的每个解决方案 但他们有更多涉及的查询 所以我很难找出问题 我做了一个小虚拟表来说明我的问题 表名 组测试 id name 1 Mel 2 L
  • pandas groupby 之后并行应用

    我用过rosetta parallel pandas easy并行化apply after groupby 例如 from rosetta parallel pandas easy import groupby to series to f
  • Rust 如何处理杀死线程?

    生成的线程之间是否存在父子连接 如果我从生成其他线程的地方杀死该线程 那些线程也会被杀死吗 这个操作系统特定吗 Rust 如何处理杀死线程 事实并非如此 没有办法杀死一个线程 也可以看看 如何从另一个线程终止或挂起一个 Rust 线 程 R
  • 使用 JavaScript 将 1 年添加到日期

    我有以下日期 2014 10 29 我试图在日期上添加一年 不是 365 天 而是 1 年 var newDate new Date 2014 10 29 newDate setDate newDate getFullYear 1 var
  • 如何使用 WaitGroup 处理错误并终止 Goroutine

    我今天一直在研究 Goroutines Channels 和 WaitGroup 在阅读了一段时间之后 我终于开始理解这个概念了 我的问题是 我不确定在这样工作时如何处理错误 主要是因为我使用了 WaitGroup 使用 WaitGroup
  • 如何在 Lisp 中一次生成一个列表中元素的所有排列?

    我已经有了生成元素列表的所有排列的代码 然而 我意识到 如果我想操作生成的列表 我需要遍历这个列表 该列表可能会很大 因此维护成本很高 我想知道是否有一种方法可以通过每次调用生成排列 以便我可以检查列表是否与我需要的匹配 如果不匹配 我将生