3
3
4
4
namespace ListDiff
5
5
{
6
- /// <summary>
7
- /// The type of <see cref="ListDiffAction{S,D}"/>.
8
- /// </summary>
9
- public enum ListDiffActionType
10
- {
11
- /// <summary>
12
- /// Update the SourceItem to make it like the DestinationItem
13
- /// </summary>
14
- Update ,
15
- /// <summary>
16
- /// Add the DestinationItem
17
- /// </summary>
18
- Add ,
19
- /// <summary>
20
- /// Remove the SourceItem
21
- /// </summary>
22
- Remove ,
23
- }
24
-
25
- /// <summary>
26
- /// A <see cref="ListDiff{S,D}"/> action that can be one of: Update, Add, or Remove.
27
- /// </summary>
28
- /// <typeparam name="S">The type of the source list elements</typeparam>
29
- /// <typeparam name="D">The type of the destination list elements</typeparam>
30
- public class ListDiffAction < S , D >
31
- {
32
- public ListDiffActionType ActionType ;
33
- public S SourceItem ;
34
- public D DestinationItem ;
35
-
36
- public ListDiffAction ( ListDiffActionType type , S source , D dest )
37
- {
38
- ActionType = type ;
39
- SourceItem = source ;
40
- DestinationItem = dest ;
41
- }
42
-
43
- public override string ToString ( )
44
- {
45
- return string . Format ( "{0} {1} {2}" , ActionType , SourceItem , DestinationItem ) ;
46
- }
47
- }
48
-
49
- /// <summary>
50
- /// Finds a diff between two lists (that contain possibly different types).
51
- /// <see cref="Actions"/> are generated such that the order of items in the
52
- /// destination list is preserved.
53
- /// The algorithm is from: http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
54
- /// </summary>
55
- /// <typeparam name="S">The type of the source list elements</typeparam>
56
- /// <typeparam name="D">The type of the destination list elements</typeparam>
57
- public class ListDiff < S , D >
58
- {
59
- /// <summary>
60
- /// The actions needed to transform a source list to a destination list.
61
- /// </summary>
62
- public List < ListDiffAction < S , D > > Actions { get ; private set ; }
63
-
64
- /// <summary>
65
- /// Whether the <see cref="Actions"/> only contain Update actions
66
- /// (no Adds or Removes).
67
- /// </summary>
68
- public bool ContainsOnlyUpdates { get ; private set ; }
69
-
70
- public ListDiff ( IEnumerable < S > sources , IEnumerable < D > destinations )
6
+ /// <summary>
7
+ /// The type of <see cref="ListDiffAction{S,D}"/>.
8
+ /// </summary>
9
+ public enum ListDiffActionType
10
+ {
11
+ /// <summary>
12
+ /// Update the SourceItem to make it like the DestinationItem
13
+ /// </summary>
14
+ Update ,
15
+ /// <summary>
16
+ /// Add the DestinationItem
17
+ /// </summary>
18
+ Add ,
19
+ /// <summary>
20
+ /// Remove the SourceItem
21
+ /// </summary>
22
+ Remove ,
23
+ }
24
+
25
+ /// <summary>
26
+ /// A <see cref="ListDiff{S,D}"/> action that can be one of: Update, Add, or Remove.
27
+ /// </summary>
28
+ /// <typeparam name="S">The type of the source list elements</typeparam>
29
+ /// <typeparam name="D">The type of the destination list elements</typeparam>
30
+ public class ListDiffAction < S , D >
31
+ {
32
+ /// <summary>
33
+ /// The type of the action.
34
+ /// </summary>
35
+ public ListDiffActionType ActionType ;
36
+ public S SourceItem ;
37
+ public D DestinationItem ;
38
+
39
+ public ListDiffAction ( ListDiffActionType type , S source , D dest )
40
+ {
41
+ ActionType = type ;
42
+ SourceItem = source ;
43
+ DestinationItem = dest ;
44
+ }
45
+
46
+ public override string ToString ( )
47
+ {
48
+ return string . Format ( "{0} {1} {2}" , ActionType , SourceItem , DestinationItem ) ;
49
+ }
50
+ }
51
+
52
+ /// <summary>
53
+ /// Finds a diff between two lists (that contain possibly different types).
54
+ /// <see cref="Actions"/> are generated such that the order of items in the
55
+ /// destination list is preserved.
56
+ /// The algorithm is from: http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
57
+ /// </summary>
58
+ /// <typeparam name="S">The type of the source list elements</typeparam>
59
+ /// <typeparam name="D">The type of the destination list elements</typeparam>
60
+ public class ListDiff < S , D >
61
+ {
62
+ /// <summary>
63
+ /// The actions needed to transform a source list to a destination list.
64
+ /// </summary>
65
+ public List < ListDiffAction < S , D > > Actions { get ; private set ; }
66
+
67
+ /// <summary>
68
+ /// Whether the <see cref="Actions"/> only contain Update actions
69
+ /// (no Adds or Removes).
70
+ /// </summary>
71
+ public bool ContainsOnlyUpdates { get ; private set ; }
72
+
73
+ public ListDiff ( IEnumerable < S > sources , IEnumerable < D > destinations )
71
74
: this ( sources , destinations , ( a , b ) => a . Equals ( b ) )
72
75
{
73
76
}
74
77
75
- public ListDiff ( IEnumerable < S > sources ,
76
- IEnumerable < D > destinations ,
77
- Func < S , D , bool > match )
78
- {
79
- if ( sources == null ) throw new ArgumentNullException ( "sources" ) ;
80
- if ( destinations == null ) throw new ArgumentNullException ( "destinations" ) ;
81
- if ( match == null ) throw new ArgumentNullException ( "match" ) ;
82
-
83
- var x = new List < S > ( sources ) ;
84
- var y = new List < D > ( destinations ) ;
85
-
86
- Actions = new List < ListDiffAction < S , D > > ( ) ;
87
-
88
- var m = x . Count ;
89
- var n = y . Count ;
90
-
91
- //
92
- // Construct the C matrix
93
- //
94
- var c = new int [ m + 1 , n + 1 ] ;
95
- for ( var i = 1 ; i <= m ; i ++ )
96
- {
97
- for ( var j = 1 ; j <= n ; j ++ )
98
- {
99
- if ( match ( x [ i - 1 ] , y [ j - 1 ] ) )
100
- {
101
- c [ i , j ] = c [ i - 1 , j - 1 ] + 1 ;
102
- }
103
- else
104
- {
105
- c [ i , j ] = Math . Max ( c [ i , j - 1 ] , c [ i - 1 , j ] ) ;
106
- }
107
- }
108
- }
109
-
110
- //
111
- // Generate the actions
112
- //
113
- ContainsOnlyUpdates = true ;
114
- GenDiff ( c , x , y , m , n , match ) ;
115
- }
116
-
117
- void GenDiff ( int [ , ] c , List < S > x , List < D > y , int i , int j , Func < S , D , bool > match )
118
- {
119
- if ( i > 0 && j > 0 && match ( x [ i - 1 ] , y [ j - 1 ] ) )
120
- {
121
- GenDiff ( c , x , y , i - 1 , j - 1 , match ) ;
122
- Actions . Add ( new ListDiffAction < S , D > ( ListDiffActionType . Update , x [ i - 1 ] , y [ j - 1 ] ) ) ;
123
- }
124
- else
125
- {
126
- if ( j > 0 && ( i == 0 || c [ i , j - 1 ] >= c [ i - 1 , j ] ) )
127
- {
128
- GenDiff ( c , x , y , i , j - 1 , match ) ;
129
- ContainsOnlyUpdates = false ;
130
- Actions . Add ( new ListDiffAction < S , D > ( ListDiffActionType . Add , default ( S ) , y [ j - 1 ] ) ) ;
131
- }
132
- else if ( i > 0 && ( j == 0 || c [ i , j - 1 ] < c [ i - 1 , j ] ) )
133
- {
134
- GenDiff ( c , x , y , i - 1 , j , match ) ;
135
- ContainsOnlyUpdates = false ;
136
- Actions . Add ( new ListDiffAction < S , D > ( ListDiffActionType . Remove , x [ i - 1 ] , default ( D ) ) ) ;
137
- }
138
- }
139
- }
140
- }
78
+ public ListDiff ( IEnumerable < S > sources ,
79
+ IEnumerable < D > destinations ,
80
+ Func < S , D , bool > match )
81
+ {
82
+ if ( sources == null ) throw new ArgumentNullException ( "sources" ) ;
83
+ if ( destinations == null ) throw new ArgumentNullException ( "destinations" ) ;
84
+ if ( match == null ) throw new ArgumentNullException ( "match" ) ;
85
+
86
+ var x = new List < S > ( sources ) ;
87
+ var y = new List < D > ( destinations ) ;
88
+
89
+ Actions = new List < ListDiffAction < S , D > > ( ) ;
90
+
91
+ var m = x . Count ;
92
+ var n = y . Count ;
93
+
94
+ //
95
+ // Construct the C matrix
96
+ //
97
+ var c = new int [ m + 1 , n + 1 ] ;
98
+ for ( var i = 1 ; i <= m ; i ++ ) {
99
+ for ( var j = 1 ; j <= n ; j ++ ) {
100
+ if ( match ( x [ i - 1 ] , y [ j - 1 ] ) ) {
101
+ c [ i , j ] = c [ i - 1 , j - 1 ] + 1 ;
102
+ }
103
+ else {
104
+ c [ i , j ] = Math . Max ( c [ i , j - 1 ] , c [ i - 1 , j ] ) ;
105
+ }
106
+ }
107
+ }
108
+
109
+ //
110
+ // Generate the actions
111
+ //
112
+ ContainsOnlyUpdates = true ;
113
+ GenDiff ( c , x , y , m , n , match ) ;
114
+ }
115
+
116
+ void GenDiff ( int [ , ] c , List < S > x , List < D > y , int i , int j , Func < S , D , bool > match )
117
+ {
118
+ if ( i > 0 && j > 0 && match ( x [ i - 1 ] , y [ j - 1 ] ) ) {
119
+ GenDiff ( c , x , y , i - 1 , j - 1 , match ) ;
120
+ Actions . Add ( new ListDiffAction < S , D > ( ListDiffActionType . Update , x [ i - 1 ] , y [ j - 1 ] ) ) ;
121
+ }
122
+ else {
123
+ if ( j > 0 && ( i == 0 || c [ i , j - 1 ] >= c [ i - 1 , j ] ) ) {
124
+ GenDiff ( c , x , y , i , j - 1 , match ) ;
125
+ ContainsOnlyUpdates = false ;
126
+ Actions . Add ( new ListDiffAction < S , D > ( ListDiffActionType . Add , default ( S ) , y [ j - 1 ] ) ) ;
127
+ }
128
+ else if ( i > 0 && ( j == 0 || c [ i , j - 1 ] < c [ i - 1 , j ] ) ) {
129
+ GenDiff ( c , x , y , i - 1 , j , match ) ;
130
+ ContainsOnlyUpdates = false ;
131
+ Actions . Add ( new ListDiffAction < S , D > ( ListDiffActionType . Remove , x [ i - 1 ] , default ( D ) ) ) ;
132
+ }
133
+ }
134
+ }
135
+ }
141
136
142
137
public static class ListDiffEx
143
138
{
@@ -151,9 +146,11 @@ public static ListDiff<T, T> MergeInto<T> (this IList<T> source, IEnumerable<T>
151
146
if ( a . ActionType == ListDiffActionType . Add ) {
152
147
source . Insert ( p , a . DestinationItem ) ;
153
148
p ++ ;
154
- } else if ( a . ActionType == ListDiffActionType . Remove ) {
149
+ }
150
+ else if ( a . ActionType == ListDiffActionType . Remove ) {
155
151
source . RemoveAt ( p ) ;
156
- } else {
152
+ }
153
+ else {
157
154
p ++ ;
158
155
}
159
156
}
@@ -171,10 +168,12 @@ public static ListDiff<TSource, TDestination> MergeInto<TSource, TDestination> (
171
168
if ( a . ActionType == ListDiffActionType . Add ) {
172
169
source . Insert ( p , create ( a . DestinationItem ) ) ;
173
170
p ++ ;
174
- } else if ( a . ActionType == ListDiffActionType . Remove ) {
171
+ }
172
+ else if ( a . ActionType == ListDiffActionType . Remove ) {
175
173
delete ( a . SourceItem ) ;
176
174
source . RemoveAt ( p ) ;
177
- } else {
175
+ }
176
+ else {
178
177
update ( a . SourceItem , a . DestinationItem ) ;
179
178
p ++ ;
180
179
}
0 commit comments