首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >更改列表中特定列表项的简单方法

更改列表中特定列表项的简单方法
EN

Stack Overflow用户
提问于 2016-11-01 23:33:36
回答 3查看 2.7K关注 0票数 3

在Clojure中,我希望将列表中的特定项(列表)与其他项进行更改。这是我的结构:

代码语言:javascript
运行
复制
(def myLis '((3 3) (5 5) (5 5)))
(def som '(4 4))

我希望用myLis更改som中的第二个元素。结果在myLis中是'((3 3) (4 4) (5 5)),这是基本的例子。我在myList里有几百种商品。我尝试assoc和更新-in,但这不能在列表上工作。

当我尝试使用assoc并更新:

代码语言:javascript
运行
复制
(update-in myLis [1] som)
(assoc myLis 1 som)
(assoc-in myLis [1] som)

犯了这样的错误:

代码语言:javascript
运行
复制
clojure.lang.PersistentList cannot be cast to clojure.lang.Associative

如何快速更改此结构中的第n个元素(列表列表)。

EN

回答 3

Stack Overflow用户

发布于 2016-11-02 09:33:14

正如克洛尔圣经(Clojure程序设计)中所指出的:

因为列表是链表,所以它们不支持有效的随机访问;因此,列表上的nth将以线性时间运行(与与向量、数组等一起使用的恒定时间相反),而且get根本不支持列表,因为这样做不符合get的次线性效率目标。

因此,为了替换列表中的元素,您必须遍历所有元素,从而在列表中运行的时间越长,并使用列表前面的元素、新项和之后的所有元素(rest)重新构建列表。或者,将列表转换为向量,如果您必须使用列表,则使用update-in并将其返回到列表中。

但是,如果可以的话,您是否可以在代码中使用序列而不是列表,这是值得的,因此您可以互换地使用向量或其他更有效地处理它们的抽象。

但是,通过列表满足基本需求的一个简单函数是:

代码语言:javascript
运行
复制
(defn list-update-in [l i x]
  (let [newlist (take i l)
        newlist (concat newlist (list x))
        newlist (concat newlist (drop (+ 1 i) l))]
    newlist))

user> (list-update-in '((1 2) (2 3) (3 4)) 1 '(8 9))
((1 2) (8 9) (3 4))

对此没有越界检查

票数 3
EN

Stack Overflow用户

发布于 2016-11-02 04:04:06

在大多数情况下,您通常应该优先使用像[1 2 3]这样的向量,而不是像'(1 2 3)这样的列表。在Clojure中,list通常用于函数调用(如(+ 1 2) ),而用于数据文字向量(通常用于[1 2 3] )。

下面的代码显示了两个可行的选项。

主要代码:

代码语言:javascript
运行
复制
(ns clj.core
  (:require 
    [tupelo.core :as t]
  ))
(t/refer-tupelo)

(def myLis [ [3 3] [5 5] [5 5] ] )
(def som [4 4] )

(spyx (assoc      myLis  1  som))
(spyx (assoc-in   myLis [1] som))

(defn -main [& args]
  (println "-main"))

结果:

代码语言:javascript
运行
复制
~/clj > lein run    
(assoc myLis 1 som)      => [[3 3] [4 4] [5 5]]
(assoc-in myLis [1] som) => [[3 3] [4 4] [5 5]]

project.clj中需要这样做才能使(spy ...)工作:

代码语言:javascript
运行
复制
:dependencies [
  [tupelo "0.9.9"] 
  ...

更新2016-11-2:

如果确实希望将所有内容都保存在列表中,可以使用replace-at 从图佩洛图书馆。它的工作方式如下:

代码语言:javascript
运行
复制
(def myLis '( (3 3) (5 5) (5 5) ) )
(def vec-1    [4 4] )
(def list-1  '(4 4) )

(spyx             (t/replace-at myLis 1 vec-1 ))
(spyx             (t/replace-at myLis 1 list-1))
(spyx (apply list (t/replace-at myLis 1 list-1)))

有结果

代码语言:javascript
运行
复制
> lein run
(t/replace-at myLis 1 vec-1)               => [(3 3) [4 4] (5 5)]
(t/replace-at myLis 1 list-1)              => [(3 3) (4 4) (5 5)]
(apply list (t/replace-at myLis 1 list-1)) => ((3 3) (4 4) (5 5))

前两个示例显示,新元素可以是任何东西,例如向量[4 4]或列表(4 4)。另外,请注意,replace-at总是返回一个向量结果。如果您希望最终结果也是一个列表,则需要使用(apply list <some-collection>)

票数 2
EN

Stack Overflow用户

发布于 2016-11-03 07:30:39

使用列表我的解决方案:

代码语言:javascript
运行
复制
(def newL '())
(def i 1)
(loop [k (- (count myLis) 1)]
  (when (> k -1)
    (cond
      (= k i) (def newL (conj newL som))
      :else (def newL (conj newL (nth myLis k)))
    )
    (recur (- k 1))
  )
)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40370240

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档