foldChannelDeltas function

List<FoldedDelta> foldChannelDeltas(
  1. Iterable<List<ChannelDelta>> perItem
)

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]!),
  ];
}