Функция поиска в clojure - PullRequest
       0

Функция поиска в clojure

0 голосов
/ 19 января 2019

Помогите мне, мне нужно написать функцию поиска, которая находит значение в списке списков, в котором каждый элемент находится в порядке (значение ключа).Например,

((key1 value1) (key2 value2) ....)

Эта функция должна быть

(look-up key list-of-lists)

и возвращает значение списка, в котором есть ключ.Например:

(look-up b '(((a b) 1) (c 2) (b 3)))3
(look-up (a b) '(((a b) 1) (c 2) (b 3)))1
(look-up d '(((a b) 1) (c 2) (b 3)))nil

У меня есть этот код:

(defn look-up [key list-of-lists]
  (if (= key (first(first list-of-lists))) (second(first list-of-lists)))
  (:else (look-up (rest list-of-lists key))))

Ответы [ 5 ]

0 голосов
/ 06 марта 2019

Вы хотите найти первый элемент в списке, который соответствует некоторым критериям (проверьте первый элемент элемента), затем вы хотите что-то сделать с этим элементом (получить его второй элемент).

Таблица Clojure рекомендует some или filter для поиска в последующем.

  • некоторые
(defn lookup
  [x col]
  (some (fn [[k v]]
          (when (= x k) v))
        col))
  • фильтр
(defn lookup
  [x col]
  (->> col
       (filter (fn [[k v]]
                 (when (= x k) v)))
       first))

  • понимание списка

Тоже хороший вариант. См. ответ Амаллоя .

  • универсальное решение, если вы хотите сойти с ума

Вы можете использовать любой из вышеперечисленных методов для этого.

(defn lookup
  [pred f col]
  (some (fn [x]
          (when (pred x)
            (f x)))
       col))

(defn lookup
  [pred f col]
  (first (for [x col :when (pred x)]
           (f x))))

;; usage: (lookup (comp '#{b} first) second data)
0 голосов
/ 21 января 2019
(defn lookup [x xs]
  (first (for [[k v] xs :when (= k x)]
           v)))
0 голосов
/ 19 января 2019

Ваш код был почти верным. Я исправил две вещи:

  • Синтаксис «если» принимает 3 аргумента: тест и два значения (для каждого логического результата теста). Нет необходимости в :else (обычно это используется для выделения ветви по умолчанию при использовании cond.

  • Рекурсивный вызов для продолжения просмотра остальной части списка списков имел аргументы в неправильном порядке.

Исправленная функция выглядит так:

(defn look-up [key list-of-lists]                                                                                                                                                    
  (if (= key (first (first list-of-lists)))                                                                                                                                          
    (second (first list-of-lists))                                                                                                                                                   
    (look-up key (rest list-of-lists))))                                                                                                                                             

;; (look-up 'b '(((a b) 1) (c 2) (b 3))) ;; => returns 3                                                                                                                             

Примечание:

  • Вы можете упростить этот код с помощью других функций, таких как ffirst, см. https://clojuredocs.org/clojure.core/ffirst
  • Вам все еще нужно улучшить его, чтобы охватить следующие случаи: 1.- пустой список и 2.- поиск ключа, которого нет. Что произойдет, если вы позвоните (look-up 'x '(((a b) 1) (c 2) (b 3)))?
0 голосов
/ 20 января 2019

Просто немного соответствия шаблону ...

(require '[meander.match.alpha :as pm])
(letfn [(lookup [KEY LIST]
            (pm/find LIST
                     (_ ... (~KEY ?v) . _ ...) ?v))]
    (let [LIST '(((a b) 1) (c 2) (b 3))]
        [(lookup 'b LIST)
         (lookup '(a b) LIST)
         (lookup 'd LIST)]))
=> [3 1 nil]

Это слишком много для такого простого случая, но он здесь, чтобы дать подсказку для некоторых более сложных вариантов использования.

0 голосов
/ 19 января 2019

Вот простая версия, которая работает:

(defn lookup
  [k lol]
  (let [the-map (into {}
                  (for [lst lol]
                    {(first lst) (second lst) } ))
        result (get the-map k)]
    result ) )

(lookup (quote b)      (quote (((a b) 1) (c 2) (b 3)))) => 3
(lookup (quote [a b])  (quote (((a b) 1) (c 2) (b 3)))) => 1
(lookup (quote d)      (quote (((a b) 1) (c 2) (b 3)))) => nil

Однако ваш код будет проще, если вы замените все списки в кавычках, такие как '(1 2 3), на векторы, такие как [1 2 3] (тогда не нужно использовать начальную кавычку), и замените все символы в кавычках, такие как 'a, на ключевые слова. как :a (также не нужно заключать символы в кавычки.

Выполнение этих изменений и добавление модульных тестов выглядит так:

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

(defn lookup
  [k lol]
  (get (into {} lol) k))

(dotest
  (is= 3    (lookup :b      [[[:a :b] 1] [:c 2] [:b 3]]))
  (is= 1    (lookup [:a :b] [[[:a :b] 1] [:c 2] [:b 3]]))
  (is= nil  (lookup :d      [[[:a :b] 1] [:c 2] [:b 3]])))

P.S. Пожалуйста, см. Brave Clojure для более подробной информации.


Обновление:

Вы не можете использовать обычную функцию с этим синтаксисом:

(look-up b '(((a b) 1) (c 2) (b 3)))

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

  1. Преобразуйте символ b в ключевое слово :b, как я предложил
  2. Всегда цитируйте символ как 'b (болезненный и подверженный ошибкам) ​​
  3. Напишите макрос (который автоматически «заключает в кавычки» все его аргументы), и пусть макрос вызывает первую версию функции lookup (много работы для небольшой выгоды).

Таким образом, я предложил пункт (1) в качестве предпочтительного решения.

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