为什么我的代码将排序的 JSON 文件解析为未排序的列表? |哈斯克尔和艾森



我正在尝试解析一个嵌套的 JSON 文件,如下所示

{
"Meta Data": {
"1: Symbol": "MSFT",
"2: Indicator": "Relative Strength Index (RSI)",
"3: Last Refreshed": "2018-10-17 10:31:05",
"4: Interval": "weekly",
"5: Time Period": 10,
"6: Series Type": "open",
"7: Time Zone": "US/Eastern Time"
},
"Technical Analysis: RSI": {
"2018-10-17 10:31:05": {
"RSI": "54.5653"
},
"2018-10-12": {
"RSI": "63.0279"
},
"2018-10-05": {
"RSI": "74.7519"
},
"2018-09-28": {
"RSI": "72.1573"
},
"2018-09-21": {
"RSI": "74.8123"
},
"2018-09-14": {
"RSI": "66.7116"
},
"2018-09-07": {
"RSI": "75.8051"
...
...
... and so on

我的目标是获得最新/最高的"RSI"值。由于键(日期(是可变的,我试图在不匹配键的情况下获取它。


这就是我到目前为止得到的

{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
module Tesst where
import           Data.Aeson
import qualified Data.ByteString.Lazy as B
import           Data.HashMap.Strict  as S
import           Data.Text
import           Data.Time
import           GHC.Exts
import           GHC.Generics
import           Network.HTTP.Conduit (simpleHttp)
newtype TechnicalAnalysis = TechnicalAnalysis {
rsiQuote  :: Object
} deriving (Show, Generic)

instance FromJSON TechnicalAnalysis where
parseJSON = withObject "RSI Quote" $
o -> do
rsiQuote <- o        .: "Technical Analysis: RSI"
return TechnicalAnalysis {..}
main :: IO ()
main = do
putStrLn "Which ticker? "
symbolToQuote <- getLine
d <- (eitherDecode <$> simpleHttp ("https://www.alphavantage.co/query?function=RSI&interval=weekly&time_period=10&series_type=open&apikey=FI2KMDSAE&symbol=" ++ symbolToQuote)) :: IO (Either String TechnicalAnalysis)
case d of
Left e   -> print e
Right qt -> print $ Prelude.map ((a, b) -> (read (unpack a) :: Day, b)) (S.toList (rsiQuote qt))

我运行代码的是这样的:

[(2005-09-02,Object (fromList [("RSI",String "60.8860")])),(2017-12-29,Object (fromList [("RSI",String "71.1921")])),(2011-09-16,Object (fromList [("RSI",String "50.3489")])),(2000-05-12,Object (fromList [("RSI",String "33.6402")]))...

如您所见,所有值都是无序的。


我的问题是:

  1. 为什么不按原样打印出该 JSON 文件?
  2. 是否可以在不排序的情况下获得最新的 RSI 值 结果?

您已经选择了本质上动态类型的Object作为语义对象。选择更好的东西;Map Day Double,例如,或者ArgMax Day Double,如果你真的只想要最新的 RSI 值,永远不会看其他任何东西。

例如:

import Control.Monad
import Data.Aeson
import Data.Aeson.Types
import Data.HashMap.Strict as S
import Data.List.NonEmpty
import Data.Semigroup
import Data.Text
import Data.Time
-- can't use readMaybe, 2018-10-17 10:31:05 has extra non-Day gunk at the end
jsonReadText :: Read a => String -> Text -> Parser a
jsonReadText err t = case reads (unpack t) of
(v,_):_ -> return v
_ -> fail $ "could not parse " ++ unpack t ++ " as " ++ err
newtype RSI = RSI Double deriving Show
instance FromJSON RSI where
parseJSON = withObject "object with RSI key" $ o -> do
t <- o .: pack "RSI"
RSI <$> jsonReadText "Double" t
newtype LatestRSI = LatestRSI (ArgMax Day RSI) deriving Show
instance FromJSON LatestRSI where
parseJSON = withObject "RSI Quote" $ o -> do
quoteMap <- o .: pack "Technical Analysis: RSI"
quotes <- forM (S.toList quoteMap) $ (dayText, rsiValue) -> do
day <- jsonReadText "Day" dayText
rsi <- parseJSON rsiValue
return (Max (Arg day rsi))
case quotes of
[] -> fail "expected non-empty collection of RSI quotes"
q:qs -> return . LatestRSI . sconcat $ q :| qs

GHCI中的用法示例:

> bs <- Data.ByteString.Lazy.readFile "test.json"
> eitherDecode bs :: Either String LatestRSI
Right (LatestRSI (Max {getMax = Arg 2018-10-17 (RSI 54.5653)}))

我能够用威廉的指示解决问题(在评论中(。

{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
module Tesst where
import           Data.Aeson
import qualified Data.ByteString.Lazy as B
import           Data.HashMap.Strict  as S
import           Data.List
import           Data.Text
import           Data.Time
import           GHC.Exts
import           GHC.Generics
import           Network.HTTP.Conduit (simpleHttp)

newtype TechnicalAnalysis = TechnicalAnalysis {
rsiQuote  :: Object
} deriving (Show, Generic)

instance FromJSON TechnicalAnalysis where
parseJSON = withObject "RSI Quote" $
o -> do
rsiQuote <- o        .: "Technical Analysis: RSI"
return TechnicalAnalysis {..}
main :: IO ()
main = do
putStrLn "Which ticker? "
symbolToQuote <- getLine
d <- (eitherDecode <$> simpleHttp ("https://www.alphavantage.co/query?function=RSI&interval=weekly&time_period=10&series_type=open&apikey=FI2KMC2DSAE&symbol=" ++ symbolToQuote)) :: IO (Either String TechnicalAnalysis)
case d of
Left e   -> print e
Right qt -> do
let l = S.toList (rsiQuote qt)
print $ maximumBy ((a, _) (b, _) -> compare a b) l

这是关键

maximumBy ((a, _) (b, _) -> compare a b)

最新更新