在涵盖Clojure for the Brave and True的部分末尾的reduce一书中,有一个挑战:
如果你想要一个能让你的头发恢复正常的运动,请尝试使用
实施map
reduce
事实证明,这比我想象的要困难得多(至少对我来说是一个Clojure初学者)。几个小时后,我想出了这个:
(defn map-as-reduce
[f coll]
(reduce #(cons (f %2) %1) '() (reverse coll)))
这是一个更好的方法吗?我特别感到沮丧的是,我必须反转输入集合才能使其正常工作。它似乎有点不雅观!
答案 0 :(得分:9)
请记住,您可以在向量的末尾高效插入:
(defn map' [f coll]
(reduce #(conj %1 (f %2)) [] coll))
示例:
(map' inc [1 2 3])
;=> [2 3 4]
此map'
与原始map
之间的一个区别是,原始map
会返回ISeq
而不只是Seqable
:
(seq? (map inc [1 2 3]))
;=> true
(seq? (map' inc [1 2 3]))
;=> false
您可以通过使用map'
撰写seq
的上述实现来解决此问题:
(defn map' [f coll]
(seq (reduce #(conj %1 (f %2)) [] coll)))
现在最重要的区别是,虽然原来的map
很懒,但这个map'
非常渴望,因为reduce
非常渴望。
答案 1 :(得分:9)
只是为了好玩: map确实接受多个集合作为参数。这是一个扩展实现:
Sub Fetch_Heures2()
Dim Wbname As String
Dim Wb As Workbook
Dim ws As Worksheet
Dim ws1 As Worksheet
Dim lngCalc As Long
Dim l
ngrow As Long
Dim lngcol As Long
'Cell C4 (date) Cell B7 (name of employee) Cell I50 (hours on site) Cell H50 (hours in office)
With Application
.ScreenUpdating = False
.EnableEvents = False
lngCalc = .CalculationState
.Calculation = xlCalculationManual
End With
Set ws1 = ThisWorkbook.Sheets("TempData")
'change folder path here
FolderName = "J:\15-0023_Vauquelin\8.0 Phase-construction\FdT fictives"
Wbname = Dir(FolderName & "\" & "*.xls*")
'ThisWorkbook.Sheets(1).UsedRange.ClearContents
Do While Len(Wbname) > 0
Set Wb = Workbooks.Open(FolderName & "\" & Wbname)
Set ws = Nothing
On Error Resume Next
'change sheet name here
Set ws = Wb.Sheets("Heures")
On Error GoTo 0
If Not ws Is Nothing Then
lngcol = 0
lngrow = lngrow + 1
lngcol = lngcol + 1
ws.Cells(4, "C").Copy ws1.Cells(lngrow, lngcol)
lngcol = lngcol + 1
ws.Cells(7, "B").Copy ws1.Cells(lngrow, lngcol)
lngcol = lngcol + 1
ws.Cells(50, "I").Copy ws1.Cells(lngrow, lngcol)
lngcol = lngcol + 1
ws.Cells(50, "H").Copy ws1.Cells(lngrow, lngcol)
End If
Wb.Close False
Wbname = Dir
Loop
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = lngCalc
End With
End Sub
在repl中:
(defn map-with-reduce
([f coll] (seq (reduce #(conj %1 (f %2)) [] coll)))
([f coll & colls]
(let [colls (cons coll colls)]
(map-with-reduce (partial apply f)
(partition (count colls)
(apply interleave colls))))))
答案 2 :(得分:7)
真实地图在其集合参数上调用seq并返回一个懒惰的seq,所以也许这可以让它更接近真实地图?
select id, 'home' as type, homeadd as address, hometel as tel from table1
Union all
select id, 'work' , workadd, worktel from table1
我会补充说,作为评论,但我没有声誉。 :)
答案 3 :(得分:2)
您可以使用conj
附加到向量而不是前置到列表中:
(defn my-map [f coll]
(reduce (fn [result item]
(conj result (f item)))
[] coll))
(my-map inc [1 2 3]) => [2 3 4]
答案 4 :(得分:2)
反转结果更常见,而不是输入。当以递归方式处理单链表时,这是一种常见的习语。它保留了这种数据结构的线性复杂性。
您可能希望为其他seq
提供不同的实现,例如:例如,矢量,可能基于conj
而不是cons
。
通过这种练习,我不会太担心优雅。
答案 5 :(得分:0)
正如已经指出的那样。您不必反转输入。 缺点是在序列的开头添加一个项目(甚至在向量上),而conj总是以最自然的方式添加,它总是以最快的方式为集合添加项目。它将从左到右添加列表,从左到右添加矢量。
我注意到大多数建议的答案都使用' reduce'所以请允许我主要使用递归建议这个:
origin/HEAD