【问题标题】:How do I filter elements from a sequence based on indexes如何根据索引从序列中过滤元素
【发布时间】:2011-12-06 09:02:33
【问题描述】:

我有一个序列s 和这个序列indexes 的索引列表。如何仅保留通过索引给出的项目?

简单示例:

(filter-by-index '(a b c d e f g) '(0 2 3 4)) ; => (a c d e)

我的用例:

(filter-by-index '(c c# d d# e f f# g g# a a# b) '(0 2 4 5 7 9 11)) ; => (c d e f g a b)

【问题讨论】:

    标签: clojure


    【解决方案1】:

    你可以使用keep-indexed:

    (defn filter-by-index [coll idxs]
      (keep-indexed #(when ((set idxs) %1) %2) 
                    coll))  
    

    另一个使用显式递归和惰性序列的版本:

    (defn filter-by-index [coll idxs]
      (lazy-seq
       (when-let [idx (first idxs)]
         (if (zero? idx)
           (cons (first coll)
                 (filter-by-index (rest coll) (rest (map dec idxs))))
           (filter-by-index (drop idx coll)
                            (map #(- % idx) idxs))))))
    

    【讨论】:

    • 这是最好的答案,而且几乎在底部!
    【解决方案2】:

    制作一个包含与索引组合的项目的向量列表,

    (def with-indexes (map #(vector %1 %2 ) ['a 'b 'c 'd 'e 'f] (range)))
    #'clojure.core/with-indexes
     with-indexes
    ([a 0] [b 1] [c 2] [d 3] [e 4] [f 5])
    

    过滤此列表

    lojure.core=> (def filtered (filter #(#{1 3 5 7} (second % )) with-indexes))
    #'clojure.core/filtered
    clojure.core=> filtered
    ([b 1] [d 3] [f 5])
    

    然后删除索引。

    clojure.core=> (map first filtered)                                          
    (b d f)
    

    然后我们将它与“最后线程”宏一起线程化

    (defn filter-by-index [coll idxs] 
        (->> coll
            (map #(vector %1 %2)(range)) 
            (filter #(idxs (first %)))
            (map second)))
    clojure.core=> (filter-by-index ['a 'b 'c 'd 'e 'f 'g] #{2 3 1 6}) 
    (b c d g)
    

    故事的寓意是,将其分解为独立的小部分,测试它们,然后将它们组合成一个工作函数。

    【讨论】:

    • 太好了,谢谢!我有类似的东西,但我无法正确使用“范围”。
    • 哦,请注意,我将索引列表切换为索引向量。这是因为集合可以用作过滤函数。
    【解决方案3】:

    最简单的解决方案是使用map

    (defn filter-by-index [coll idx]
      (map (partial nth coll) idx))
    

    【讨论】:

      【解决方案4】:

      我喜欢 Jonas 的回答,但是这两个版本都不适用于无限的索引序列:第一个版本尝试创建一个无限集,而后者在彼此之上遇到 layering too many unrealized lazy sequences 的堆栈溢出。为了避免这两个问题,您必须做更多的手动工作:

      (defn filter-by-index [coll idxs]
        ((fn helper [coll idxs offset]
           (lazy-seq
            (when-let [idx (first idxs)]
              (if (= idx offset)
                (cons (first coll)
                      (helper (rest coll) (rest idxs) (inc offset)))
                (helper (rest coll) idxs (inc offset))))))
         coll idxs 0))
      

      有了这个版本,collidxs 都可以无限大,你仍然没有问题:

      user> (nth (filter-by-index (range) (iterate #(+ 2 %) 0)) 1e6)
      2000000
      

      编辑:不要试图挑出乔纳斯的答案:没有其他解决方案适用于无限索引序列,这就是为什么我觉得需要一个解决方案。

      【讨论】:

      • 我想知道哪个是更遥远的边缘情况,要保留的索引的无限序列,或者不是单调递增顺序的索引。
      • @AlexTaggart 好点,因为不可能同时满足两者我想你必须做出决定。作为一般 Clojure 哲学的一部分,懒惰对我来说似乎更重要,但对于给定的问题实例,它很容易出错。
      【解决方案5】:

      我有一个类似的用例,并想出了另一个简单的解决方案。这个需要向量。

      我已更改函数名称以匹配其他类似的 clojure 函数。

      (defn select-indices [coll indices]
         (reverse (vals (select-keys coll indices))))
      

      【讨论】:

        【解决方案6】:
        (defn filter-by-index [seq idxs]
          (let [idxs (into #{} idxs)]
            (reduce (fn [h [char idx]]
                      (if (contains? idxs idx)
                        (conj h char) h))
                    [] (partition 2 (interleave seq (iterate inc 0))))))
        
        (filter-by-index [\a \b \c \d \e \f \g] [0 2 3 4])
        =>[\a \c \d \e]
        

        【讨论】:

          【解决方案7】:
          => (defn filter-by-index [src indexes]
               (reduce (fn [a i] (conj a (nth src i))) [] indexes))
          
          => (filter-by-index '(a b c d e f g) '(0 2 3 4))
          [a c d e]
          

          【讨论】:

            【解决方案8】:

            我知道这不是被问到的,但是在阅读了这些答案后,我意识到在我自己的个人用例中,我真正想要的基本上是通过掩码过滤。

            所以这是我的看法。希望这对其他人有帮助。

            (defn filter-by-mask [coll mask]
              (filter some? (map #(if %1 %2) mask coll)))
            
            (defn make-errors-mask [coll]
              (map #(nil? (:error %)) coll))
            

            用法

            (let [v [{} {:error 3} {:ok 2} {:error 4 :yea 7}]
                data ["one" "two" "three" "four"]
                mask (make-errors-mask v)]
                (filter-by-mask data mask))
            
            ; ==> ("one" "three")
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-10-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多