1 #!/usr/bin/perl
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 use strict;
49 use warnings;
50 use Data::Dumper;
51
52 my @accounts = (
53 ["A", "a1\@a.com", "a2\@a.com"],
54 ["B", "b1\@b.com"],
55 ["A", "a3\@a.com", "a1\@a.com"]
56 );
57 merge_accounts(@accounts);
58 merge_accounts_full(@accounts);
59
60 @accounts = (
61 ["A", "a1\@a.com", "a2\@a.com"],
62 ["B", "b1\@b.com"],
63 ["A", "a3\@a.com"],
64 ["B", "b2\@b.com", "b1\@b.com"]
65 );
66 merge_accounts(@accounts);
67 merge_accounts_full(@accounts);
68
69 @accounts = (
70 ["A", "a1\@a.com", "a2\@a.com"],
71 ["B", "b1\@b.com"],
72 ["A", "a3\@a.com"],
73 ["B", "b2\@b.com", "b1\@b.com"],
74 ["A", "a3\@a.com", "a2\@a.com"],
75 );
76 merge_accounts(@accounts);
77 merge_accounts_full(@accounts);
78
79
80
81
82
83
84 sub merge_accounts_ {
85 my $accounts = shift;
86 my $result = [];
87 foreach my $elem (@$accounts) {
88 my $did_merge = 0;
89
90
91
92 foreach my $i (0..$#$result) {
93 if (can_merge_to($elem, $result->[$i])) {
94 $result->[$i] = merge($result->[$i], $elem);
95 $did_merge = 1;
96 last;
97 }
98 }
99 push @$result, $elem unless $did_merge;
100 }
101 return $result;
102 }
103
104
105
106
107
108
109 sub merge {
110 my ($elem1, $elem2) = @_;
111 my $seen;
112 map { $seen->{$_} = 1 } @$elem1;
113 foreach my $part (@$elem2) {
114 next if $seen->{$part};
115 push @$elem1, $part;
116 }
117 return $elem1;
118 }
119
120
121
122
123 sub can_merge_to {
124 my ($elem1, $elem2) = @_;
125 my $seen;
126 map { $seen->{$_} = 1 } @$elem1;
127 my $name = $elem2->[0];
128 return 0 unless $name eq $elem1->[0];
129 foreach my $part (@$elem2) {
130 next if $part eq $name;
131 return 1 if $seen->{$part};
132 }
133 return 0;
134 }
135
136
137
138
139 sub merge_accounts {
140 my $accounts = [ @_ ];
141 print "Input: [";
142 foreach my $elem (@$accounts) {
143 print " [" . join(", ", @$elem) . "]\n";
144 }
145 print "]\n";
146
147 my $merged = merge_accounts_($accounts);
148
149 print "Output: [";
150 foreach my $elem (@$merged) {
151 print " [" . join(", ", @$elem) . "]\n";
152 }
153 print "]\n";
154 }
155
156
157
158
159
160
161 sub merge_accounts_full {
162 my $accounts = [ @_ ];
163 print "Input: [";
164 foreach my $elem (@$accounts) {
165 print " [" . join(", ", @$elem) . "]\n";
166 }
167 print "]\n";
168
169 my $merged = merge_accounts_($accounts);
170
171 while(is_same_deeply($accounts, $merged) == 0) {
172 $accounts = $merged;
173 $merged = merge_accounts_($accounts);
174 }
175
176 print "Output: [";
177 foreach my $elem (@$merged) {
178 print " [" . join(", ", @$elem) . "]\n";
179 }
180 print "]\n";
181 }
182
183
184
185 sub is_same_deeply {
186 my ($list1, $list2) = @_;
187 if(scalar(@$list1) != scalar(@$list2)) {
188 return 0;
189 }
190
191 return 1 unless @$list1;
192 foreach my $i (0..$#$list1) {
193 if(ref($list1->[$i]) ne ref($list2->[$i])) {
194 return 0;
195 }
196 if(ref($list1->[$i]) eq "ARRAY") {
197 return 0 unless is_same_deeply($list1->[$i], $list2->[$i]);
198 }
199 }
200 return 1;
201 }
202