Список слияния карт и объединения оценивает наборам в Clojure

Какую функцию я могу поместить как НЕЧТО здесь для получения верный в конце? Я играл с установленным на хеш (только корректный для первых 2 значений), союз и concat, но я знаю, что не обрабатываю одноэлементное по сравнению с установленным условием правильно только с ни одним из тех.

(defn mergeMatches [propertyMapList]
    "Take a list of maps and merges them combining values into a set"
    (reduce #(merge-with FOO %1 %2) {} propertyMapList))

(def in 
    (list
        {:a 1}
        {:a 2}
        {:a 3}
        {:b 4}
        {:b 5}
        {:b 6} ))

(def out
    { :a #{ 1 2 3}
      :b #{ 4 5 6} })

; this should return true
(= (mergeMatches in) out)

Что самый идиоматический путь состоит в том, чтобы обработать это?

12
задан Alex Miller 4 February 2010 в 21:05
поделиться

6 ответов

Это подойдет:

(let [set #(if (set? %) % #{%})]
  #(clojure.set/union (set %) (set %2)))

Перепишите более прямо для примера (Алекс):

(defn to-set [s]
    (if (set? s) s #{s}))
(defn set-union [s1 s2] 
    (clojure.set/union (to-set s1) (to-set s2)))
(defn mergeMatches [propertyMapList]
    (reduce #(merge-with set-union %1 %2) {} propertyMapList))
12
ответ дан 2 December 2019 в 05:27
поделиться

Другое решение, предложенное @wmacgyver в Twitter на основе мультиотображений :

(defn add
  "Adds key-value pairs the multimap."
  ([mm k v]
     (assoc mm k (conj (get mm k #{}) v)))
  ([mm k v & kvs]
     (apply add (add mm k v) kvs)))
(defn mm-merge
  "Merges the multimaps, taking the union of values."
  [& mms]
  (apply (partial merge-with union) mms))   

(defn mergeMatches [property-map-list]
  (reduce mm-merge (map #(add {} (key (first %)) (val (first %))) property-map-list)))      
3
ответ дан 2 December 2019 в 05:27
поделиться

Кажется, это работает:

(defn FOO [v1 v2]
      (if (set? v1)
          (apply hash-set v2 v1)
          (hash-set v1 v2)))
2
ответ дан 2 December 2019 в 05:27
поделиться

«Неизменяемая замена образца стиля JavaBean» может выражаться именованными параметрами и при необходимости аннотацией @ BeanProperty:

import reflect._
case class A(@BeanProperty val x: String, @BeanProperty val y : Int)

A(x = "s", y = 3)
A(y = 3, x = "s")

Добавление методов (точнее: определение нового интерфейса) имеет смысл только в статически типизированном языке, если клиент знает о новых методах и может компилировать их по интерфейсу. С помощью структурного типирования клиенты могут определять методы, которые, как ожидается, будут присутствовать в объекте. Компилятор Scala преобразует структурный тип в код отражения, который может завершиться сбоем во время выполнения.

type T = {def go(x : Int): Int }
def y(any : Any) = any.asInstanceOf[T].go(2)

class A{
  def go(x : Int) = x + 1
}
y(new A())
y(new {}) //this will fail

Новые классы или признаки можно определить с помощью интерпретатора на лету. Метод Interpret преобразует код Scala в байтовый код.

Вы уже упомянули о ScalaSigParser , с которым непросто работать.

Я думаю, что остальных функций, которые вам нравятся, еще нет.

-121--2863490-

Я не вижу ничего плохого в этом подходе. Этот метод можно найти под разными именами в целом ряде рамок, например StartMessenger в Zend Framework . Обычно сеанс переносится в объект вместо обычного массива сеанса и с помощью ViewHelper вместо функции.

Чтобы убедиться в отсутствии опечаток в клавишах сеанса при назначении сообщения, можно также преобразовать код назначения в функцию, например,

function set_message($text, $type)
{
    $_SESSION['message'] = array(
        'text' => $text,
        'type' => $type
    );
}

Вы можете улучшить его, если функция возвращает последовательности вместо эхо , и лично я использую sprintf для форматирования вывода. Делает код несколько более читаемым imho, например

return sprintf('<div id="message-box" class="type-%s">%s</div>',
                $_SESSION["message"]["text"], 
                $_SESSION["message"]["type"]);

Как отметил @ Gumbo, функция может не работать, когда Сеансы не работают, но это, вероятно, наложит ряд других проблем для всего приложения тогда, так что я бы точно не беспокоился об этой конкретной части кода тогда.

Незначительная вещь: $ _ SESSION является сверхглобальным , поэтому не нужно использовать ключевое слово global .

-121--5044484-

Не супер красиво, но это работает.

(defn mergeMatches [propertyMapList]
    (for [k (set (for [pp propertyMapList] (key (first pp))))]
         {k (set (remove nil? (for [pp propertyMapList] (k pp))))}))
2
ответ дан 2 December 2019 в 05:27
поделиться

Я этого не писал, но это был вклад от @амитратуры в Twitter:

(defn kv [bag [k v]] 
  (update-in bag [k] conj v))
(defn mergeMatches [propertyMapList]
  (reduce #(reduce kv %1 %2) {} propertyMapList))
5
ответ дан 2 December 2019 в 05:27
поделиться

Я бы не стал использовать merge - для этого

(defn fnil [f not-found]
  (fn [x y] (f (if (nil? x) not-found x) y)))
(defn conj-in [m map-entry]
  (update-in m [(key map-entry)] (fnil conj #{}) (val map-entry)))
(defn merge-matches [property-map-list]
  (reduce conj-in {} (apply concat property-map-list)))

user=> (merge-matches in)
{:b #{4 5 6}, :a #{1 2 3}}

fnil скоро станет частью ядра, так что вы можете игнорировать реализацию... но она просто создает версию другой функции, которая может обрабатывать нулевые аргументы. В этом случае конъюнктура заменит #{} на nil.

Таким образом, сокращение, соединяющее с множеством для каждого ключа/значения в списке поставляемых карт.

4
ответ дан 2 December 2019 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: