我想合并一个由元素和字符串组成的元组的列表,每个char与该元素在一起。
例如:[(True,“ xy”),(False,“ abc”)]-> [(True,'x'),(True,'y'),(False,'a'), (False,'b'),(False,'c')]
我确实有解决方案,但是我想知道是否有更好的解决方案:
concatsplit :: [(a,[b])] -> [(a,b)]
concatsplit a = concatMap (\(x,y)-> concatsplit' (x,y)) a
concatsplit' :: (a,[b]) -> [(a,b)]
concatsplit' y = map (\x -> ((fst y),x)) (snd y)
答案 0 :(得分:8)
列表推导通常可以完成高阶函数,而且我认为,如果您不需要更改数据,而只需“解压缩”数据,它们就很清楚了。这是一个工作示例:
concS :: [(a,[b])] -> [(a,b)]
concS ls = [(a,b) | (a,x) <- ls, b <- x]
答案 1 :(得分:3)
sequenceA
非常简单:
concatsplit = concatMap sequenceA
或将其进一步推广:
concatsplit = (>>= sequenceA)
详细信息:
sequenceA
的类型为(Applicative f, Traversable t) => t (f a) -> f (t a)
。这意味着,如果您的类型在“外部”上带有Traversable
,在“内部”上带有Applicative
,则可以在其上调用sequenceA
将其内外翻,因此Applicative
位于“外部”,而Traversable
位于“内部”。(True, "xy")
的类型为(Bool, [Char])
,其类型为(,) Bool ([] Char)
。 Traversable
的{{1}}中有an instance,((,) a)
的{{1}}中有an instance。因此,您可以在其上调用Applicative
,其结果将为[]
类型或sequenceA
加糖。[] ((,) Bool Char)
不仅具有有用的类型,而且它确实满足您在此需要的事情(并且实际上与[(Bool, Char)]
等效)。sequenceA
的类型为concatsplit'
。 concatMap
的类型为Foldable t => (a -> [b]) -> t a -> [b]
。当专门用于列表时,除了参数相反的顺序之外,其他内容都相同。答案 2 :(得分:3)
其他答案显示了如何从头开始习惯地执行此操作,对此我非常喜欢。展示如何完善现有内容也可能很有趣。再次提醒您:
using (var client = new HttpClient())
{
string query;
using (var content = new FormUrlEncodedContent(new Dictionary<string, string>()
{
{"username", username},
{"password", password}
}))
{
query = content.ReadAsStringAsync().Result;
}
var model = new{
username = txtUsername.Text,
password = txtPassword.Text
};
var json = JsonConvert.SerializeObject(model);
var user = new StringContent(json, Encoding.UTF8, "application/json");
using (var response = await client.PostAsync(@"http://localhost/dataagent/api/user/authenticate", user))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
// handle result here
}
}
}
我要不断更改的第一件事称为“ eta缩减”,它是将concatsplit a = concatMap (\(x,y)-> concatsplit' (x,y)) a
concatsplit' y = map (\x -> ((fst y),x)) (snd y)
形状的物体变成\x -> foo x
的形状。我们可以在foo
的参数中做到这一点
concatMap
,然后再次在concatsplit a = concatMap concatsplit' a
的参数中获取:
concatsplit
看看concatsplit = concatMap concatsplit'
,我最不喜欢的是使用concatsplit'
和fst
而不是模式匹配。通过模式匹配,它看起来像这样:
snd
如果您真的想练习减少eta,您可能会注意到concatsplit' (a,bs) = map (\x -> (a,x)) bs
可以加前缀并将其更改为
(,)
但是我认为我也很高兴。在这一点上,这个定义很小,我很想将其内联到concatsplit' (a,bs) = map (\x -> (,) a x) bs
= map ((,) a) bs
本身,得到:
concatsplit
对我来说,这似乎是一个很好的定义,我会停在那里。
您可能在这里几乎被eta-减少所困扰:放下concatsplit = concatMap (\(a,bs) -> map ((,) a) bs)
几乎是正确的形状。高级用户可能会继续,并注意:
bs
因此,通过一些eta减少和其他无点技术,我们可以采用这种方式过渡:
uncurry (\a bs -> map ((,) a) bs) = \(a,bs) -> map ((,) a) bs
但是,就我个人而言,我发现它的可读性不如我在上面停下来的地方,即:
concatsplit = concatMap (uncurry (\a bs -> map ((,) a) bs))
= concatMap (uncurry (\a -> map ((,) a)))
= concatMap (uncurry (map . (,)))
答案 3 :(得分:1)
您还可以将monad实例用于列表:
concatSplit l = l >>= \(a,x) -> x >>= \b -> return (a,b)
可以简化为:
concatSplit l = l >>= \(a,x) -> map ((,) a) x
并重新格式化为do
表示法
concatSplit l = do
(a,x) <- l
map ((,) a) x