Algorithm 合并';空间';元组

Algorithm 合并';空间';元组,algorithm,f#,Algorithm,F#,我有三个元组列表,每个元组包含(startpos、endpos、value) 我想做的是将它们合并到一个元组列表中(startpos、endpos、values[]),但遵循一条规则,我发现绘制比编写更容易: //third [---------] [------------] //second [-------------] [---------------------------] //

我有三个元组列表,每个元组包含(startpos、endpos、value)

我想做的是将它们合并到一个元组列表中(startpos、endpos、values[]),但遵循一条规则,我发现绘制比编写更容易:

//third               [---------]                    [------------]
//second        [-------------]              [---------------------------]
//first   [-----------------------------]    [--------------]
//(pos)   0123456789|123456789|123456789|123456789|123456789|123456789|123456789
//result  [--1-][--2-][---3---][---1----]    [---2--][---3--]
(结果中的数字表示每个结果元素的值[]列表的预期长度)

基本上,我只保留一个“较高”的元素,它与一个“较低”的元素重叠,并将其拆分为“同质”元素

可将这些位置视为
int
类型。从结果中可以看出,“分割”线段的起点和终点不在同一位置,而是在位置1或位置+1处。只要定义了值的顺序,值的顺序就不重要

样本数据(基于上述示例):

现在我发现很难用一种功能性的方式来思考这个问题,任何出现在脑海中的事情都是必须的。也许在这种情况下这是不可避免的,但如果有人有任何想法

更新事实上,如果我们将输入的大小写概括为已经是类型(
int*int*List
),我们可以只处理两个输入列表的大小写,然后将其折叠


PS:这不是家庭作业,也不是代码高尔夫,我只是对数据进行了一些消毒。

你的
后的
数据是错误的;至少我的程序认为是这样,我也相信这一点

let third=[(12,22,3.1);(43,56,3.2)]
设秒=[(6,20,2.1);(35,63,2.2)]
让第一个=[(0,30,1.1);(35,50,1.2)]
let all=List.concat[第一;第二;第三]
设min=all |>Seq.map(fun(x,y,z)->x)|>Seq.min
设max=all |>Seq.map(fun(x,y,z)->y)|>Seq.max
让我们设置每个值=
[最小..最大]
|>List.map(乐趣i->
i、 全部
|>List.filter(乐趣(x,y,z)->x z))
printfn“%A”设置每个值
设x1,l1=Seq.nth 0设置每个值
让结果=
设置每个值
|>List.fold(fun((l,h,s)::t)作为上一个)(nx,ns)->
如果s=ns,则(l,nx,s)::t其他(nx,nx,ns)::prev
)[x1,x1,l1]
|>List.rev
let after=[
(0,5,[1.1]); 
(6,11,[1.1;2.1]); 
(12,20,[1.1;2.1;3.1]); 
(21,30,[1.1]); 
(35,42,[1.2;2.2]); 
(43,50,[1.2;2.2;3.2]) 
] 
打印fn“”
printfn“%A”结果
打印fn“”
printfn“%A”之后
断言(结果=之后)
策略:首先,我将整个范围内的每个数字映射到“它所在的集合”。然后我折叠,播种,第一个结果是
(min,min,setminisin)
,每一步,如果集合没有改变,我只是扩大范围,否则如果集合确实改变,我制作一个新元素


在折叠中输入var名称的键:
l
ow、
h
igh、
s
et、
nx
-next x、
ns
-next set

您的
数据错误后的
;至少我的程序认为是这样,我也相信这一点

let third=[(12,22,3.1);(43,56,3.2)]
设秒=[(6,20,2.1);(35,63,2.2)]
让第一个=[(0,30,1.1);(35,50,1.2)]
let all=List.concat[第一;第二;第三]
设min=all |>Seq.map(fun(x,y,z)->x)|>Seq.min
设max=all |>Seq.map(fun(x,y,z)->y)|>Seq.max
让我们设置每个值=
[最小..最大]
|>List.map(乐趣i->
i、 全部
|>List.filter(乐趣(x,y,z)->x z))
printfn“%A”设置每个值
设x1,l1=Seq.nth 0设置每个值
让结果=
设置每个值
|>List.fold(fun((l,h,s)::t)作为上一个)(nx,ns)->
如果s=ns,则(l,nx,s)::t其他(nx,nx,ns)::prev
)[x1,x1,l1]
|>List.rev
let after=[
(0,5,[1.1]); 
(6,11,[1.1;2.1]); 
(12,20,[1.1;2.1;3.1]); 
(21,30,[1.1]); 
(35,42,[1.2;2.2]); 
(43,50,[1.2;2.2;3.2]) 
] 
打印fn“”
printfn“%A”结果
打印fn“”
printfn“%A”之后
断言(结果=之后)
策略:首先,我将整个范围内的每个数字映射到“它所在的集合”。然后我折叠,播种,第一个结果是
(min,min,setminisin)
,每一步,如果集合没有改变,我只是扩大范围,否则如果集合确实改变,我制作一个新元素

在折叠中输入var名称的键:
l
ow、
h
igh、
s
et、
nx
-next x、
ns
-next set

完成重写(请参见编辑),更短、更优雅,可能可读性更低。仍在扼杀布赖恩的逻辑

更新:至少在上述测试中,现在可以正常工作了

let third =  [(12,22,3.1);(43,56,3.2)]
let second = [(6,20,2.1);(35,63,2.2)]
let first =  [(0,30,1.1);(35,50,1.2)]

//===helper functions===
// foldable combined min and max finder
let minmax (mn,mx) (x,y,_) = (min mn x, max mx y)  
// test if x - y range overlaps position i
let overlaps i (x,y,_) = x<=i && i<=y 
// get third element from triple
let getz (_,_,z) = z              

//specialise function, given two tuples, will combine lists (L & U)
//  but only if both lists have contents AND their indexes (il & iu) 
//  are not more than 1 apart, i is included simply so that we can pass 
//  merge directly to the List.map2 below
let merge (i,il,L) (_,iu,U) = 
     if L = [] || U = [] || iu - il > 1 then 
        (i, il, L) 
     else  
        (i, iu, L @ U)

let input = [first;second;third] // input data - 'bottom' first
//find max and min positions
let (x0,yn) = input |> Seq.concat |> Seq.fold minmax (0,0) 

//transform each data list to a list of (i,[z])
let valsByPos = input |> List.map (fun level -> //for each data 'level' 
                [x0..yn] |> List.map (fun i ->   //for each position in range
                     //collect values of all elements in level that
                     // overlap this position
                     (i, level |> List.filter (overlaps i) |> List.map getz)))

// 'merge up' each level, keeping only upper values if lower values exist
// after we will have just one list of (i, [z])
let mergedValsByPos = valsByPos //offside here for SO formatting
          //add an index into each tuple
          |> List.mapi (fun i l -> l |> List.map (fun (j,z) -> (j,i,z)))  
          //use index to determine if we should 'merge up' for each subsublst
          |> List.reduce (List.map2 merge) 
          //rip the index back out                     
          |> List.map (fun (i,_,z) -> (i,z)) 

//get first value as seed for fold
let x1,l1 = Seq.nth 0 mergedValsByPos

//transform list (i,[z]) into list of (x,y,[z])
//key: (l)ow, (h)igh, (s)et, (nx)-next x, (ns)-next set
let result = 
    mergedValsByPos 
    //first remove any positions where there are no values
    |> List.filter (fun el -> snd(el) <> [])
    //double capture on state so we can take all or part of it
    |> List.fold (fun (((l,h,s)::t) as prev) (nx,ns) -> 
                    //if [z] value hasn't changed, we just enlarge range
                    //  of current state (from (l,h) to (l,nx)) 
                    //  otherwise we add a new element (nx,nx,ns) to state
                    if s=ns then (l,nx,s)::t else (nx,nx,ns)::prev 
                ) [x1,x1,l1] //initial state from seed values
    |> List.rev //folded value is backwards (because of::), so reverse
let third=[(12,22,3.1);(43,56,3.2)]
设秒=[(6,20,2.1);(35,63,2.2)]
让第一个=[(0,30,1.1);(35,50,1.2)]
//==辅助函数===
//可折叠组合最小和最大查找器
设minmax(mn,mx)(x,y,)=(minmnx,max-mx-y)
//测试x-y范围是否与位置i重叠
设重叠i(x,y,u)=x Seq.concat |>Seq.fold minmax(0,0)
//将每个数据列表转换为(i,[z])
让valsByPos=input |>List.map(乐趣级别->//对于每个数据“级别”
[x0..yn]|>List.map(乐趣i->//范围内的每个位置
//收集该级别中所有元素的值
//重叠此位置
(i,level |>List.filter(重叠i)|>List.map getz)))
//“向上合并”每个级别,如果存在较低的值,则仅保留较高的值
//之后,我们将只有一个列表(i,[z])
让mergedValsByPos=valsByPos//在此处越位以进行SO格式化
//在每个元组中添加索引
|>List.mapi(funil->l |>List.map(fun(j,z)->(j,i,z)))
//使用索引来确定是否应该为每个子子项“合并”
|>List.reduce(List.map2合并)
//把索引撕下来
|>List.map(fun(i,z)->(i,z))
//获取第一个值作为折叠的种子
设x1,l1=Seq.nth 0 mergedValsByPos
//将列表(i,[z])转换为
let third =  [(12,22,3.1);(43,56,3.2)] 
let second = [(6,20,2.1);(35,63,2.2)] 
let first =  [(0,30,1.1);(35,50,1.2)] 

let all = List.concat [first; second; third]
let min = all |> Seq.map (fun (x,y,z)->x) |> Seq.min 
let max = all |> Seq.map (fun (x,y,z)->y) |> Seq.max

let setsEachValueIsIn =
    [min..max] 
    |> List.map (fun i -> 
        i, all 
            |> List.filter (fun (x,y,z) -> x<=i && i<=y) 
            |> List.map (fun (x,y,z) -> z))

printfn "%A" setsEachValueIsIn

let x1,l1 = Seq.nth 0 setsEachValueIsIn

let result = 
    setsEachValueIsIn 
    |> List.fold (fun (((l,h,s)::t) as prev) (nx,ns) -> 
                    if s=ns then (l,nx,s)::t else (nx,nx,ns)::prev
                ) [x1,x1,l1]
    |> List.rev

let after =  [ 
                (0,5,[1.1]); 
                (6,11,[1.1;2.1]); 
                (12,20,[1.1;2.1;3.1]); 
                (21,30,[1.1]); 
                (35,42,[1.2;2.2]); 
                (43,50,[1.2;2.2;3.2]) 
             ] 

printfn ""
printfn "%A" result
printfn ""
printfn "%A" after
assert(result = after)
let third =  [(12,22,3.1);(43,56,3.2)]
let second = [(6,20,2.1);(35,63,2.2)]
let first =  [(0,30,1.1);(35,50,1.2)]

//===helper functions===
// foldable combined min and max finder
let minmax (mn,mx) (x,y,_) = (min mn x, max mx y)  
// test if x - y range overlaps position i
let overlaps i (x,y,_) = x<=i && i<=y 
// get third element from triple
let getz (_,_,z) = z              

//specialise function, given two tuples, will combine lists (L & U)
//  but only if both lists have contents AND their indexes (il & iu) 
//  are not more than 1 apart, i is included simply so that we can pass 
//  merge directly to the List.map2 below
let merge (i,il,L) (_,iu,U) = 
     if L = [] || U = [] || iu - il > 1 then 
        (i, il, L) 
     else  
        (i, iu, L @ U)

let input = [first;second;third] // input data - 'bottom' first
//find max and min positions
let (x0,yn) = input |> Seq.concat |> Seq.fold minmax (0,0) 

//transform each data list to a list of (i,[z])
let valsByPos = input |> List.map (fun level -> //for each data 'level' 
                [x0..yn] |> List.map (fun i ->   //for each position in range
                     //collect values of all elements in level that
                     // overlap this position
                     (i, level |> List.filter (overlaps i) |> List.map getz)))

// 'merge up' each level, keeping only upper values if lower values exist
// after we will have just one list of (i, [z])
let mergedValsByPos = valsByPos //offside here for SO formatting
          //add an index into each tuple
          |> List.mapi (fun i l -> l |> List.map (fun (j,z) -> (j,i,z)))  
          //use index to determine if we should 'merge up' for each subsublst
          |> List.reduce (List.map2 merge) 
          //rip the index back out                     
          |> List.map (fun (i,_,z) -> (i,z)) 

//get first value as seed for fold
let x1,l1 = Seq.nth 0 mergedValsByPos

//transform list (i,[z]) into list of (x,y,[z])
//key: (l)ow, (h)igh, (s)et, (nx)-next x, (ns)-next set
let result = 
    mergedValsByPos 
    //first remove any positions where there are no values
    |> List.filter (fun el -> snd(el) <> [])
    //double capture on state so we can take all or part of it
    |> List.fold (fun (((l,h,s)::t) as prev) (nx,ns) -> 
                    //if [z] value hasn't changed, we just enlarge range
                    //  of current state (from (l,h) to (l,nx)) 
                    //  otherwise we add a new element (nx,nx,ns) to state
                    if s=ns then (l,nx,s)::t else (nx,nx,ns)::prev 
                ) [x1,x1,l1] //initial state from seed values
    |> List.rev //folded value is backwards (because of::), so reverse