当值(对于某事物的id)正在改变时及时写入记录

时间:2011-07-26 11:48:39

标签: f#

当某事物的id值发生变化时,如何及时写下记录?当ture-> false和false->为某些列表时为每条记录的id?

例如表

id value
 1 0
 2 0
 2 0
 2 0
 1 0
 2 1 --> the only changes here
 2 1
 1 0
 2 0 --> and here (node with id 2 changed 1 -> 0 )
 1 1 --> node with id 1 changed 0 -> 1     

结果表

2 1
2 0
1 1

我的想法不起作用,有点奇怪,我正在考虑功能性或linq制作相同的方法。

                        let oop = ref (filteredsq
                                       |> Seq.distinctBy(fun (node,v,k) -> k) 
                                       |> Seq.map(fun (node,v,k) -> k, false )
                                       |> Array.ofSeq )
                        [for (node,value,key) in filteredsq do
                            let i = ref 0
                            for (k,v) in !oop do
                                if key = k && value <> v then
                                    (!oop).[!i] <- (k,value)
                                    yield node
                            i := !i + 1 ]

谢谢

5 个答案:

答案 0 :(得分:3)

我认为如果您定义如下函数:

let getChanges f items =
  items
  |> Seq.map (fun x -> f x, x)
  |> Seq.pairwise
  |> Seq.choose (fun ((a, _), (b, x)) -> if a <> b then Some x else None)

然后你可以这样做:

filteredsq
|> Seq.groupBy (fun (_, _, k) -> k)
|> Seq.collect (fun (_, items) ->
  items 
  |> getChanges (fun (_, value, _) -> value)
  |> Seq.map (fun (node, _, _) -> node))
|> Seq.toList

答案 1 :(得分:1)

我会做像

这样的事情
List
|> List.toSeq
|> Seq.pairwise
|> Seq.pick (fun ((fa,fb),(sa,sb)) -> if fb <> sb then Some(sa,sb) else None)

答案 2 :(得分:1)

<强>更新

open System.Collections.Generic

let filter (acc:'a) (f:('a -> 'b -> bool * 'a)) (s:'b seq) = 
    let rec iter (acc:'a) (e:IEnumerator<'b>) = 
        match e.MoveNext() with
        | false -> Seq.empty 
        | true -> match f acc e.Current with
                  | (true,newAcc) -> seq { yield e.Current; yield! iter newAcc e}
                  | (false,newAcc) -> seq { yield! iter newAcc e}
    iter acc (s.GetEnumerator())

let skipUntilChange (f : 'a -> 'b) (s : 'a seq) = 
    s |> Seq.skip 1
    |> filter (s |> Seq.head |> f)
        (fun a b -> if a = f b then false,f b else true,f b)

[(1,0);(2,0);(2,0);(2,0);(1,0);(2,1);(2,1);(1,0);(2,0);]
|> Seq.mapi (fun c (i,v) -> (i,v,c))
|> Seq.groupBy (fun (i,v,c) -> i)
|> Seq.map (snd >> skipUntilChange (fun (_,v,_) -> v))
|> Seq.concat |> Seq.sortBy (fun (i,v,c) -> c)
|> Seq.map (fun (i,v,c) -> (i,v))
|> printfn "%A"

答案 3 :(得分:1)

我不确定我是否完全理解您的问题,但以下根据您的样本给出正确的输出。我们的想法是首先过滤掉没有正确密钥的值,然后使用Seq.pairwaise(如jpalmer的解决方案)来查找值发生变化的位置:

let input = [ (1, 0); (2, 0); (2, 0); (2, 0); (1, 0); (2, 1); (2, 1); (1, 0); (2, 0) ]

let findValueChanges key input =
  input 
  |> Seq.filter (fun (k, v) -> k = key) // Get values with the right key
  |> Seq.pairwise                       // Make tuples with previous & next value
  |> Seq.filter (fun ((_, prev), (_, next)) -> prev <> next) // Find changing points
  |> Seq.map snd                        // Return the new key-value pair (after change)

如果您想查找所有不同密钥的更改,则可以使用Seq.groupBy查找所有可能的密钥(然后您不需要findValueChanges中的第一行):

input 
|> Seq.groupBy fst
|> Seq.map (fun (k, vals) -> findValueChanges k vals)

(对于您的输入,键1的值没有变化,因为值始终为1, 0

答案 4 :(得分:1)

我只是使用内部可变字典来跟踪每个键的最后看到的值,并且当任何值与该键的最后一个值不同时,得到(键,值):

let filterChanges (s:('a*'b) seq) =   
    let dict = new System.Collections.Generic.Dictionary<'a,'b>()
    seq {
        for (key,value) in s do
            match dict.TryGetValue(key) with
            | false,_ -> dict.[key] <- value
            | true,lastValue -> 
                if lastValue <> value then
                    yield (key,value)
                    dict.[key] <- value
    }

测试:

> filterChanges [(1,0);(2,0);(2,0);(2,0);(1,0);(2,1);(2,1);(1,0);(2,0);(1,1)];;
val it : seq<int * int> = seq [(2, 1); (2, 0); (1, 1)]