11from functools import reduce
2- from typing import Dict , List , Set
2+ from typing import Dict , List , Set , Tuple
33
44from .pointer import Pointer
55from .types import Diffable
66
77
8- def diff_lists (input : List , output : List , ptr : Pointer ) -> List :
9- memory = {(0 , 0 ): {"ops" : [], "cost" : 0 }}
8+ def diff_lists (input : List , output : List , ptr : Pointer ) -> Tuple [ List , List ] :
9+ memory = {(0 , 0 ): {"ops" : [], "rops" : [], " cost" : 0 }}
1010
1111 def dist (i , j ):
1212 if (i , j ) not in memory :
@@ -17,18 +17,22 @@ def dist(i, j):
1717 if i > 0 :
1818 base = dist (i - 1 , j )
1919 op = {"op" : "remove" , "idx" : i - 1 }
20+ rop = {"op" : "add" , "idx" : i - 1 , "value" : input [i - 1 ]}
2021 paths .append (
2122 {
2223 "ops" : base ["ops" ] + [op ],
24+ "rops" : base ["rops" ] + [rop ],
2325 "cost" : base ["cost" ] + 1 ,
2426 }
2527 )
2628 if j > 0 :
2729 base = dist (i , j - 1 )
2830 op = {"op" : "add" , "idx" : j - 1 , "value" : output [j - 1 ]}
31+ rop = {"op" : "remove" , "idx" : j - 1 }
2932 paths .append (
3033 {
3134 "ops" : base ["ops" ] + [op ],
35+ "rops" : base ["rops" ] + [rop ],
3236 "cost" : base ["cost" ] + 1 ,
3337 }
3438 )
@@ -40,18 +44,23 @@ def dist(i, j):
4044 "original" : input [i - 1 ],
4145 "value" : output [j - 1 ],
4246 }
47+ rop = {
48+ "op" : "replace" ,
49+ "idx" : i - 1 ,
50+ "original" : output [j - 1 ],
51+ "value" : input [i - 1 ],
52+ }
4353 paths .append (
4454 {
4555 "ops" : base ["ops" ] + [op ],
56+ "rops" : base ["rops" ] + [rop ],
4657 "cost" : base ["cost" ] + 1 ,
4758 }
4859 )
4960 step = min (paths , key = lambda a : a ["cost" ])
5061 memory [(i , j )] = step
5162 return memory [(i , j )]
5263
53- ops = dist (len (input ), len (output ))["ops" ]
54-
5564 def pad (state , op ):
5665 ops , padding = state
5766 if op ["op" ] == "add" :
@@ -71,46 +80,54 @@ def pad(state, op):
7180 return [ops + [full_op ], padding - 1 ]
7281 else :
7382 replace_ptr = ptr .append (op ["idx" ] + padding )
74- replace_ops = diff (op ["original" ], op ["value" ], replace_ptr )
83+ replace_ops , _ = diff (op ["original" ], op ["value" ], replace_ptr )
7584 return [ops + replace_ops , padding ]
7685
77- padded_ops , _ = reduce (pad , ops , [[], 0 ])
86+ solution = dist (len (input ), len (output ))
87+ padded_ops , _ = reduce (pad , solution ["ops" ], [[], 0 ])
88+ padded_rops , _ = reduce (pad , reversed (solution ["rops" ]), [[], 0 ])
7889
79- return padded_ops
90+ return padded_ops , padded_rops
8091
8192
82- def diff_dicts (input : Dict , output : Dict , ptr : Pointer ) -> List :
83- ops = []
93+ def diff_dicts (input : Dict , output : Dict , ptr : Pointer ) -> Tuple [ List , List ] :
94+ ops , rops = [], []
8495 input_keys = set (input .keys ())
8596 output_keys = set (output .keys ())
8697 for key in input_keys - output_keys :
87- ops .append ({"op" : "remove" , "path" : ptr .append (key ), "key" : key })
98+ ops .append ({"op" : "remove" , "path" : ptr .append (key )})
99+ rops .insert (0 , {"op" : "add" , "path" : ptr .append (key ), "value" : output [key ]})
88100 for key in output_keys - input_keys :
89101 ops .append (
90102 {
91103 "op" : "add" ,
92104 "path" : ptr .append (key ),
93- "key" : key ,
94105 "value" : output [key ],
95106 }
96107 )
108+ rops .insert (0 , {"op" : "remove" , "path" : ptr .append (key )})
97109 for key in input_keys & output_keys :
98- ops .extend (diff (input [key ], output [key ], ptr .append (key )))
99- return ops
110+ key_ops , key_rops = diff (input [key ], output [key ], ptr .append (key ))
111+ ops .extend (key_ops )
112+ key_rops .extend (rops )
113+ rops = key_rops
114+ return ops , rops
100115
101116
102- def diff_sets (input : Set , output : Set , ptr : Pointer ) -> List :
103- ops = []
117+ def diff_sets (input : Set , output : Set , ptr : Pointer ) -> Tuple [ List , List ] :
118+ ops , rops = [], []
104119 for value in input - output :
105- ops .append ({"op" : "remove" , "path" : ptr .append (value ), "value" : value })
120+ ops .append ({"op" : "remove" , "path" : ptr .append (value )})
121+ rops .insert (0 , {"op" : "add" , "path" : ptr .append ("-" ), "value" : value })
106122 for value in output - input :
107- ops .append ({"op" : "add" , "path" : ptr .append (value ), "value" : value })
108- return ops
123+ ops .append ({"op" : "add" , "path" : ptr .append ("-" ), "value" : value })
124+ rops .insert (0 , {"op" : "remove" , "path" : ptr .append (value )})
125+ return ops , rops
109126
110127
111- def diff (input : Diffable , output : Diffable , ptr : Pointer = None ) -> List :
128+ def diff (input : Diffable , output : Diffable , ptr : Pointer = None ) -> Tuple [ List , List ] :
112129 if input == output :
113- return []
130+ return [], []
114131 if ptr is None :
115132 ptr = Pointer ()
116133 if isinstance (input , list ) and isinstance (output , list ):
@@ -119,4 +136,6 @@ def diff(input: Diffable, output: Diffable, ptr: Pointer = None) -> List:
119136 return diff_dicts (input , output , ptr )
120137 if isinstance (input , set ) and isinstance (output , set ):
121138 return diff_sets (input , output , ptr )
122- return [{"op" : "replace" , "path" : ptr , "value" : output }]
139+ return [{"op" : "replace" , "path" : ptr , "value" : output }], [
140+ {"op" : "replace" , "path" : ptr , "value" : input }
141+ ]
0 commit comments