Clojure - смесь "получить" и "nth"? - PullRequest
2 голосов
/ 04 марта 2020

Я изо всех сил пытаюсь найти функцию, которая найдет счастливую середину между функцией get и nth. Я проводил много исследований этих функций типа последовательности, кто-нибудь знает обходной путь для этого или знает функцию, которая выполняет функцию как таковую?

Мне нужна способность nth захватывать подсписки:

=> (nth '(1 (2 3) 4 5) 1)
(2 3)
=> (get 1 '(1 (2 3) 4 5))
nil

И мне нужна способность get возвращать «ноль», когда он выходит за пределы диапазона:

=> (get -1 '(1 (2 3) 4 5))
nil
=> (nth '(1 (2 3) 4 5) -1)
Execution error (IndexOutOfBoundsException) at user/eval149 (REPL:1).
null

Мне нужен этот код для рекурсивной функции sub-seq:

(defn sub-seq [coll i j]
  (nth coll i)
  (if (< i (+ i j))
    (sub-seq coll (inc' i) j)
  )
)

( Функция sub-seq должна возвращать элементы 'j', начиная с позиции 'i'.)

Вот несколько примеров выходных данных для того, что я пытаюсь написать:

=> (sub-seq '(1 2 (3 4) (5 (6 7))) 1 2))
(2 (3 4))
=> (sub-seq '(1 2 3 4 5 6 7) 2 4)
(3 4 5 6)

I наконец-то приступил к работе, спасибо всем за помощь:

(defn sub-seq [coll i j]
  (conj
    (list*
      (nth coll i nil)
      (if (> j 1)
        (sub-seq coll (+ i 1) (- j 1))))))

Ответы [ 2 ]

4 голосов
/ 04 марта 2020

nth принимает необязательный третий аргумент not-found. Вы можете использовать его для предоставления значения по умолчанию, если ваш индекс выходит за пределы:

user=> (nth '(1 (2 3) 4 5) -1)
Execution error (IndexOutOfBoundsException) at user/eval1 (REPL:1).
null
user=> (nth '(1 (2 3) 4 5) -1 nil)
nil

Если бы у вас был вектор, вы могли бы использовать subvec напрямую:

(let [s [1 2 3 4 5 6 7]]
  (subvec s 2 6))

Если у вас есть последовательность, которую вы могли бы написать:

(defn subsequence [coll start n]
  (->> coll
       (drop start)
       (take n)))

(subsequence '(1 2 (3 4) (5 (6 7))) 1 2)
=> (2 (3 4))
(subsequence '(1 2 3 4 5 6 7) 2 4)
=> (3 4 5 6)

Примечание: при написании программы Clojure часто вы можете решить свою проблему проще с помощью обработки последовательности. Иногда необходимы рекурсивные алгоритмы, но часто вы можете обойтись с богатым набором функций Clojure, которые работают с последовательностями.

2 голосов
/ 04 марта 2020

Вы неправильно поняли get. Он работает с ассоциативными коллекциями, такими как карты и векторы. Рассмотрим:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(dotest
  (let [data-list '(1 (2 3) 4 5)
        data-vec (vec data-list) ]
    (spyx (nth data-list 1))
    (spyx (nth data-vec 1))
    (spyx (get data-list 1))
    (spyx (get data-vec 1))
    ))

с результатом

(nth data-list 1)  => (2 3)
(nth data-vec 1)   => (2 3)
(get data-list 1)  => nil
(get data-vec 1)   => (2 3)

Поскольку список Clojure не является ассоциативным, как карта, list вообще не следует использовать со списками. В идеале get будет выдавать исключение при передаче аргумента списка, чтобы указать, что он не работает с ними.


Для вашей конкретной цели c, возможно, просто сделайте что-то вроде:

(take j
  (drop i coll))

Для получения дополнительной документации, пожалуйста, обзор здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...