foldChannelDeltas function
Groups deltas by their shape, keeping the order they were built in.
perItem is one list per compared thing, which is what lets items mean
anything: folding one item's deltas is foldChannelDeltas([item.deltas])
and every row comes back with items: 1, harmlessly.
Input order is kept, most-repeated not first. ComparedItem.deltas
already builds in channel order — pixels, tree, texts, events — and ranking
by count would put the noisiest shape at the top of every report, which is
the opposite of what a reader wants. What handles the noise is the count on
the row and the channel it names, not its position.
Implementation
List<FoldedDelta> foldChannelDeltas(Iterable<List<ChannelDelta>> perItem) {
var order = <String>[];
var first = <String, ChannelDelta>{};
var counts = <String, int>{};
var items = <String, int>{};
for (var deltas in perItem) {
var seenHere = <String>{};
for (var delta in deltas) {
// Base and head are pointedly not in the key: an identity hash that
// differs on every occurrence is the case this exists for, and grouping
// on the value would put every occurrence in a group of its own.
var key = [
delta.channel,
delta.subchannel ?? '',
delta.subject ?? '',
delta.property ?? '',
].join('\u0000');
if (first.putIfAbsent(key, () => delta) == delta && counts[key] == null) {
order.add(key);
}
counts[key] = (counts[key] ?? 0) + 1;
if (seenHere.add(key)) items[key] = (items[key] ?? 0) + 1;
}
}
return [
for (var key in order)
FoldedDelta(delta: first[key]!, count: counts[key]!, items: items[key]!),
];
}