- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试学习 Haskell,并且我正在尝试创建一个函数,该函数采用列表列表并按等价总和对子列表进行分组。这不是家庭作业。
import Data.List
let x = [[1,2],[2,1],[5,0],[0,3],[1,9]]
let groups = groupBy (\i j -> sum i == sum j) x
[[[1,2],[2,1]],[[5,0]],[[0,3]],[[1,9]]]
[[1,2],[2,1]]
分组在一起,但不与
[0,3]
.为什么是这样?
map
,但我似乎无法让它发挥作用。
最佳答案
groupBy
函数保留输入顺序,因此是可逆的。如果你愿意扔掉这些信息,你可以使用以下代码
import Data.List (foldl')
import Data.Map (elems,empty,insertWith')
bucketBy :: Ord b => (a -> b) -> [a] -> [[a]]
bucketBy eq = elems . foldl' go empty
where go m l = insertWith' (++) (eq l) [l] m
*Main> bucketBy sum x[[[0,3],[2,1],[1,2]],[[5,0]],[[1,9]]]
The application of elems
from Data.Map gives a clue for what’s happening.
elems :: Map κ α -> [α]
O(n). Return all elements of the map in the ascending order of their keys.
elems (fromList [(5,"a"), (3,"b")]) == ["b","a"]
elems empty == []
A Map associates values of some type κ with values of another possibly distinct type α. In the example from your question, you start with x
whose type is
*Main> :type xx :: [[Integer]]
That is, x
is a list of integer lists. The type of the resulting partition of x
you want is
*Main> :t [[[0,3],[2,1],[1,2]],[[5,0]],[[1,9]]][[[0,3],[2,1],[1,2]],[[5,0]],[[1,9]]] :: Num τ => [[[τ]]]
or a list of lists where each of the latter lists are themselves lists that all have the same sum. The Num τ =>
bit is a context that constrains the type τ to be an instance of the typeclass Num
. Happy for us, Integer
is such a type:
*Main> :info Integerdata Integer…instance Num Integer -- Defined in GHC.Num…
We know then that the type of the partition is [[[Integer]]]
. This typeclass nonsense may seem unnecessarily fussy, but we’ll need the concept again in just a moment. (To give you an idea of what’s going on, the typechecker doesn’t have enough information to decide whether the literal 0
, for example, is of type Int
or Integer
.)
Each sublist contains lists with the same sum. In other words, there exists a mapping from a sum to a list of integer lists. Therefore, the type of the Map used in bucketBy
must resemble
Map Integer [[Integer]]
[ [0,3]
, [2,1]
, [1,2]
]
foldl
Haskell 中的和friends 允许你在列表的元素之间“插入”一个运算符,从列表左端的零值开始。例如,
[5,3,9,1]
的总和表示为左折叠是
((((0 + 5) + 3) + 9) + 1)
foldl (+) 0 [5,3,9,1]
bucketBy
的定义包含
elems . foldl' go empty
Map Integer [[Integer]]
类型,我们折叠的零值是该类型的空 Map,和
go
以某种方式将列表的每个连续值添加到 map 中。
foldl'
是
foldl
的严格表亲,但严格性超出了这个答案的范围。 (另见
“Stack overflow” on HaskellWiki。)
foldl'
的类型
*Main> :t foldl'foldl' :: (a -> b -> a) -> a -> [b] -> a
we should have three arguments in the application, but only two are present in the code above. This is because the code is written in point-free style. Your list is there implicitly due to partial application of foldl'
.
Think back to the sum-as-fold example above. The type of that application without the final argument is
*Main> :t foldl (+) 0foldl (+) 0 :: Num b => [b] -> b
Partial application allows us to create new functions. Here we defined a function that computes a number from some list of numbers. Hmm, sounds familiar.
*Main> :t sumsum :: Num a => [a] -> a
The .
combinator expresses function composition. Its name is chosen to resemble the notation g∘f as commonly seen in mathematics textbooks to mean “do f first and then compute g from the result.” This is exactly what’s happening in the definition of bucketBy
: fold the list of values into a Map and then get the values of out the Map.
In your comment, you asked about the purpose of m
. With an explicit type annotation, we might define go
as
...
where go :: Map Integer [[Integer]] -> [Integer] -> Map Integer [[Integer]]
go m l = insertWith' (++) (eq l) [l] m
m
是我们目前积累的Map,
l
是下一个
Integer
我们想要扔到适当的桶中的列表。回想一下
eq
是外部
bucketBy
的参数.
insertWith'
控制新项目如何进入 map 。 . (按照惯例,名称以尾随引号结尾的函数是严格的变体。)
(++)
组合器附加列表。申请
eq l
为
l
确定合适的存储桶.
l
而不是
[l]
,结果将是
*Main> bucketBy sum x[[0,3,2,1,1,2],[5,0],[1,9]]
but then we lose the structure of the innermost lists.
We’ve already constrained the type of bucketBy
's result to be [[[α]]]
and thus the type of the Map's elements. Say the next item l
to fold is [1,2]
. We want to append, (++)
, it to some other list of type [[Integer]]
, but the types don’t match.
*Main> [[0,3],[2,1]] ++ [1,2]<interactive>:1:21: No instance for (Num [t0]) arising from the literal `2' Possible fix: add an instance declaration for (Num [t0]) In the expression: 2 In the second argument of `(++)', namely `[1, 2]' In the expression: [[0, 3], [2, 1]] ++ [1, 2]
Wrapping l
gets us
*Main> [[0,3],[2,1]] ++ [[1,2]][[0,3],[2,1],[1,2]]
You might stop with
bucketBy :: ([Integer] -> Integer) -> [[Integer]] -> [[[Integer]]]
bucketBy eq = elems . foldl' go empty
where go m l = insertWith' (++) (eq l) [l] m
bucketBy :: ([Integer] -> Integer) -> [[Integer]] -> [[[Integer]]]
bucketBy eq = elems . foldl' go empty
where go :: Map Integer [[Integer]] -> [Integer] -> Map Integer [[Integer]]
go m l = insertWith' (++) (eq l) [l] m
y
定义为
y :: [[Int]]
y = [[1,2],[2,1],[5,0],[0,3],[1,9]]
x
几乎相同,
bucketBy
对
y
没有用.
*Main> bucketBy sum y<interactive>:1:15: Couldn't match expected type `Integer' with actual type `Int' Expected type: [[Integer]] Actual type: [[Int]] In the second argument of `bucketBy', namely `y' In the expression: bucketBy sum y
Let’s assume you can’t change the type of y
for some reason. You might copy-and-paste to create another function, say bucketByInt
, where the only change is replacing Integer
with Int
in the type annotations.
This would be highly, highly unsatisfying.
Maybe later you have some list of strings that you want to bucket according to the length of the longest string in each. In this imaginary paradise you could
*Main> bucketBy (maximum . map length) [["a","bc"],["d"],["ef","g"],["hijk"]][[["d"]],[["ef","g"],["a","bc"]],[["hijk"]]]
What you want is entirely reasonable: bucket some list of things using the given criterion. But alas
*Main> bucketBy (maximum . map length) [["a","bc"],["d"],["ef","g"],["hijk"]]<interactive>:1:26: Couldn't match expected type `Integer' with actual type `[a0]' Expected type: Integer -> Integer Actual type: [a0] -> Int In the first argument of `map', namely `length' In the second argument of `(.)', namely `map length'
Again, you may be tempted to write bucketByString
, but by this point, you’re ready to move away and become a shoe cobbler.
The typechecker is your friend. Go back to your definition of bucketBy
that’s specific to Integer
lists, simply comment out the type annotation and ask its type.
*Main> :t bucketBybucketBy :: Ord k => (b -> k) -> [b] -> [[b]]
Now you can apply bucketBy
for the different cases above and get the expected results. You were already in paradise but didn’t know it!
Now, in keeping with good style, you provide annotations for the toplevel definition of bucketBy
to help the poor reader, perhaps yourself. Note that you must provide the Ord
constraint due to the use of insertWith'
, whose type is
insertWith' :: Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
go
提供注释。 ,但这需要使用
scoped type variables extension .
{-# LANGUAGE ScopedTypeVariables #-}
import Data.List (foldl')
import Data.Map (Map,elems,empty,insertWith')
bucketBy :: forall a b. Ord b => (a -> b) -> [a] -> [[a]]
bucketBy eq = elems . foldl' go empty
where go :: Map b [a] -> a -> Map b [a]
go m l = insertWith' (++) (eq l) [l] m
bucketBy :: Ord b => (a -> b) -> [a] -> [[a]]
Could not deduce (b ~ b1) from the context (Ord b) bound by the type signature for bucketBy :: Ord b => (a -> b) -> [a] -> [[a]] at prog.hs:(10,1)-(12,46) `b' is a rigid type variable bound by the type signature for bucketBy :: Ord b => (a -> b) -> [a] -> [[a]] at prog.hs:10:1 `b1' is a rigid type variable bound by the type signature for go :: Map b1 [a1] -> a1 -> Map b1 [a1] at prog.hs:12:9 In the return type of a call of `eq' In the second argument of `insertWith'', namely `(eq l)' In the expression: insertWith' (++) (eq l) [l] m
This is because the typechecker treats the b
on the inner type annotation as a distinct and entirely unrelated type b1
even though a human reader plainly sees the intent that they be the same type.
Read the scoped type variables documentation for details.
You may wonder where the outer layer of brackets went. Notice that the type annotation generalized from
bucketBy :: ([Integer] -> Integer) -> [[Integer]] -> [[[Integer]]]
bucketBy :: forall a b. Ord b => (a -> b) -> [a] -> [[a]]
[Integer]
本身是另一种类型,这里表示为
a
.
关于haskell - 使用 Haskell 根据等效总和对子列表值进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9950039/
我基本上有三个表: hunt_c_usershunt_c_collected_eggshunt_c_achievements 我目前只使用 hunt_c_users 和 hunt_c_collecte
我已经计算了不同表中计数的总和。这会执行两次,每个 performanceID 一次。现在我想得到两个总和的总和。 下面是我目前做的两个总和的代码: SELECT SUM((COUNT (Bo
我有一个对 2 个值求和的脚本。我计划添加更多值(value),但首先我需要让它发挥作用。人们告诉我给他们 NUMBER 值,所以我这样做了,但现在它甚至没有给出输出。 base = 0; $("#F
我正在尝试计算在我们的数据库中跟踪的花费总额。每个订单文档包含一个字段“total_price” 我正在尝试使用以下代码: db.orders.aggregate({ $group: {
给定 Excel 2013(或更高版本)中的 2 个命名表: tbl发票 ID InvRef Total 1 I/123 45 2 I/234
希望你们一切都好。我来这里是因为我从今天早上开始就试图解决一个问题,我再也受不了了。 这就是上下文:我有一个 excel 工作簿,其中有不同的工作表,其中包含不同国家/地区的不同商业计划。我的目标是制
我有一份报告显示客户订购的产品及其价格: CompanyA Product 7 14.99 CompanyA Product 3 45.95 CompanyA Prod
我使用此python客户端: https://github.com/ryananguiano/python-redis-timeseries 如何汇总所有匹配? ts = TimeSeries(cli
希望创建一个总和和计数公式,该公式将自动调整以适应范围内插入的新行。 例如,如果我在单元格 D55 中有公式 =SUM(D17:D54)。每次我在该范围内插入新行时,我都需要更改公式的顶部范围来解释它
所以,我需要聚合日期相同的行。 到目前为止,我的代码返回以下内容: date value source 0 2018-04-08 15:52:26.1
我有数字输入 数量约为 30 我需要将它们全部汇总到一个字段 我拥有的在下面 查看:
您好,我正在尝试根据以下数据计算过去三个月中出现不止一次的不同帐户 ID 的数量;我想要 2 作为查询结果,因为 test1@gmail.com 和 test2@gmail.com 出现超过 1 次。
我有两个带有以下字段的表: ... orders.orderID orders.orderValue 和 payments.orderID payments.payVal 在 payments.pay
我想按 image_gallery 和 video_gallery 两列的 DESC 进行排序。 SELECT b.*, c.title as category, (S
实际上我的原始数据库为 SELECT sum(data1,data2) as database_value,sum(data3,data4) as database_not_value from t
我试图获取三个分数中每一个的值并将它们相加并显示在“总计:”中。我的问题是,我不知道如何做到这一点,以便每次其中一个分数值发生变化时,相应的总分值也会随之变化。 我可以在某处调用“onchange”来
如何获得按第一个值分组的元组列表中第二个和第三个值的总和? 即: list_of_tuples = [(1, 3, 1), (1, 2, 4), (2, 1, 0), (2, 2, 0)] expec
我正在尝试将我的列表中的整数转换为列表的总和和平均值,并说明任何低于冰点 F<32 的温度。每当我尝试获取总和或平均值时,我都会收到错误提示“+: 'int' 和 'str' 不支持的操作数类型”。我
在我的 ios 项目中,我使用了两个实体 (CoreData):具有一对多关系的 Person 和 Gifts 我知道如何计算给一个人的礼物总和: NSDecimalNumber *orderSum=
我有两个表(输入和类别): CREATE TABLE categories ( iId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, sNam
我是一名优秀的程序员,十分优秀!