我们说我有这个阵列:
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
元组中的第一个int
向第二个int
报告。
我可以用
轻松映射let orgMap = Map.ofArray reporting
从那里,我可以很容易地得到所有使用
报告到2的整数列表orgMap
|> Map.filter (fun _ key -> key = 2)
返回
map [(3, 2); (4, 2)]
然而,我真正希望看到的是整个结构,从2开始。例如,我想找到一种可以为我提供样本输出的方法
map [(3, 2); (4, 2); (5, 3); (6, 4); (7, 3)]
如果我正在找人2或
map [(5, 3); (7, 3)]
如果我对第3个人感兴趣。
我可以这样做吗?如果是这样,怎么样?除了map
之外还有其他结构可以更好地实现这一目标吗?
提前感谢您的帮助。
答案 0 :(得分:1)
我假设你想得到一对带有"数字"的一对整数的列表。直接或间接向某些" root"报告。 这是一个简单但效率低下的解决方案:
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
let reportStructureSet =
reportStructure |> Set.ofArray
let reportingDirectlyTo root raportsToSet =
raportsToSet
|> Set.filter(fun (_, key) -> key = root)
let addNextGeneration previousIteration raportsToSet =
let numbersLowerInHierarchy = previousIteration |> Set.map fst
raportsToSet |> Set.filter(
// select only those elements from raportsToSet...
fun (num, supervisor) ->
// ...which either are already in previousIteration
(Set.contains (num, supervisor) previousIteration) ||
// ...or are "below" someone from previousIteration
(Set.contains supervisor numbersLowerInHierarchy))
let reportingDirectlyOrIndirectlyTo root raportsToSet =
// applies addNextGeneration until is "stabilizes" on some value
let rec fixPointHelper previousIteration =
let nextIteration = addNextGeneration previousIteration raportsToSet
if nextIteration = previousIteration
then nextIteration
else fixPointHelper nextIteration
// set of numbers directly reporting to root
let reportsDirectly = reportingDirectlyTo root raportsToSet
// start "iteration" using numbers directly reporting to root
fixPointHelper reportsDirectly
let reportingDirectlyOrIndirectlyToList root raportsToSet =
reportingDirectlyOrIndirectlyTo root raportsToSet
|> Set.toList
如果您想实施有效的解决方案,则应以下列方式将reportStructureSet
解释为图表:
int
是顶点int
s是有向边然后只需检查哪些边缘可以从" root"使用DFS。
答案 1 :(得分:1)
由于OCaml接近F#并尝试在F#中找到拓扑排序,因此我没有找到任何有用的东西,而是查找了OCaml代码。
我发现An Introduction to Objective Caml使用深度优先搜索解决了您的问题并将其用作此答案的基础。另外,因为您是F#的新手,您可以查看该文档并查看代码的派生方式。奇怪的是,在发布这篇文章之后,我看了一下文档的其余部分,他在文档中有一个更高级的DFS版本。
您的输入是一个数组[| |]
,但您的答案是一个列表[]
,因此我将大部分工作作为列表。
答案的顺序与您的顺序不同,但它们的格式相同。
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
//
// 6 -> 4 -> 2
// 5 -> 3 -> 2 -> 1
// 7 -> 3
// val revStructure : tl:('a * 'b) list -> ('b * 'a) list
let revStructure tl = List.map (fun (a,b) -> (b,a)) tl
// val mem : item:'a -> list:'a list -> bool when 'a : equality
let mem item list = List.exists (fun x -> x = item) list
// val successors : n:'a -> edges:('a * 'b) list -> 'b list when 'a : equality
let successors n edges =
let matching (s,_) = s = n
List.map snd (List.filter matching edges)
// val dist : pred:'a -> succs:'b list -> ('a * 'b) list
let dist pred succs = List.map (fun y -> (pred,y)) succs
// val dfsPairs : edges:('a * 'a) list -> start:'a -> ('a * 'a) list when 'a : equality
let dfsPairs edges start =
let rec dfsPairsInner edges visited start result =
match start with
| [] -> List.rev (revStructure result)
| n::nodes ->
if mem n visited then
dfsPairsInner edges visited nodes result
else
let predecessors = dist n (successors n edges)
let result =
match predecessors with
| [] -> result
| _ -> predecessors @ result
dfsPairsInner edges (n::visited) ((successors n edges) @ nodes) result
dfsPairsInner edges [] [start] []
let revEdges = revStructure (List.ofArray reportStructure)
let result = dfsPairs revEdges 2
// val result : (int * int) list = [(4, 2); (3, 2); (7, 3); (5, 3); (6, 4)]
let result = dfsPairs revEdges 3
// val result : (int * int) list = [(7, 3); (5, 3)]
答案 2 :(得分:0)
我喜欢f#谜题,所以我对这个捅了一下。我希望你喜欢。
let orgList = [(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)]
let orgMap =
orgList
|> List.fold (fun acc item ->
let key = snd item
match Map.tryFind key acc with
| Some(value) ->
let map' = Map.remove key acc
Map.add(key) (item::value) map'
| None ->
Map.add(key) (item::[]) acc
) Map.empty<int, (int*int) list>
let findReports supervisor =
let rec findReports' acc collection =
match collection with
| head::tail ->
(findReports' (head::acc) tail)
@ match Map.tryFind (fst head) orgMap with
| Some(value) -> (findReports' [] value)
| None -> []
| [] -> acc
findReports' [] (Map.find supervisor orgMap)
findReports 2
|> List.map fst
|> List.distinct
返回
val it : int list = [3; 4; 5; 7; 6]
findReports 2
返回
val it : (int * int) list = [(3, 2); (4, 2); (5, 3); (7, 3); (6, 4)]
我打破它以澄清。
let orgList = [ (1, 2); (1, 3); (1, 4); (2, 5); (3, 6); (4, 5); (5, 6); (5, 7) ]
我们将您的元组列表创建为((报告,老板)列表的老板功能映射)。这可称为邻接列表,用于遍历图形。
let orgMap =
orgList
|> List.fold (fun acc item ->
let key = snd item
match Map.tryFind key acc with
如果老板下有报告列表,请添加到该列表中。
| Some(reports) ->
let map' = Map.remove key acc
Map.add(key) (item::reports) map'
否则,添加到空列表并插入字典。
| None ->
Map.add(key) (item::[]) acc
以空地图作为累加器开始。
) Map.empty<int, (int*int) list>
通过项目递归查找所有报告。
let findReports supervisor =
let rec findReports' acc collection =
match collection with
如果有项目,请将其附加到累加器。这是BFS。如果在连接运算符(@)之前和之后切换表达式,它将变为DFS。
| head::tail ->
(findReports' (head::acc) tail)
将当前列表连接到报告的递归报告列表。
@ match Map.tryFind (fst head) orgMap with
| Some(value) -> (findReports' [] value)
| None -> []
如果在列表的末尾,则返回列表。
| [] -> acc
运行递归函数。
findReports' [] (Map.find supervisor orgMap)
运行该功能。
findReports 7
仅返回报告
|> List.map fst
不要两次报告报告。
|> List.distinct