Как объединить объекты Aeson?

У меня есть список таких объектов aeson

[object ["key1" .= "value1"], object ["key2" .= "value2"]] 

и я хочу объединить их как один объект aeson, подобный этому

object ["key1" .= "value1", "key2" .= "value2"]

Это вполне стандартно при работе с данными JSON на других языках (операция слияния), но я не вижу ничего подобного в библиотеке Aeson.

Я просто что-то упустил, и можно ли это сделать с помощью какой-то стандартной функции haskell? Я пытался использовать sequence, но кажется, что JSON Value не является монадой, поэтому я не могу этого сделать.

Мне не нужно иметь дело с глубоким слиянием или дублированием ключей, я просто хочу сгенерировать что-то вроде

{
  "key1": value1,
  "key2": value2
}

от

[{ "key1": value1 }, { "key2": value2 }]

person Batou99    schedule 07.06.2017    source источник
comment
Если у вас есть объекты с типами Object, то это просто HashMap, поэтому вы можете использовать HashMap.union, mappend, (<>) и т. д. Но если у вас есть объекты с типами Value, как вы хотите их объединить? Например, у вас есть строка и число, какой должен быть результат?   -  person freestyle    schedule 07.06.2017
comment
Мне просто нужно поведение unions. Мне нужна карта со всеми ключами и их значениями, и если какой-то ключ дублируется, я с радостью позволю последнему перезаписать другие. По сути то же самое поведение, которое вы получаете на Ruby при выполнении hash1.merge(hash2)   -  person Batou99    schedule 08.06.2017


Ответы (1)


Учитывая, что список содержит только объекты JSON (таким образом, элементы с парами ключ-значение или элементы с Object конструктор), вы можете написать свой собственный:

import Data.Aeson(Value(Object))
import qualified Data.HashMap.Lazy as HML

merge_aeson :: [Value] -> Value
merge_aeson = Object . HML.unions . map (\(Object x) -> x)

Если мы проверим вышеуказанную функцию с заданным образцом входных данных, мы получим:

Prelude Data.Aeson HML> merge_aeson [object ["key1" .= "value1"], object ["key2" .= "value2"]] 
Object (fromList [("key2",String "value2"),("key1",String "value1")])
person Willem Van Onsem    schedule 07.06.2017
comment
Функция сохраняет первое (самое раннее) значение в случае наличия одного и того же ключа более чем в одной из объединенных записей. Стратегия «Первые победы» исходит из стратегии Data.HashMap.Lazy. - person user855443; 24.06.2020
comment
@ user855443: вы можете использовать foldl (unionsWith ...) empty для указания другой стратегии: hackage.haskell.org/package/unordered-containers-0.2.11.0/docs/ вы можете, например, использовать const для выбора первого (самого раннего) или const id чтобы выбрать последний (последний). Или вы даже можете реализовать более сложную стратегию - person Willem Van Onsem; 24.06.2020