diff options
| author | Copilot <198982749+Copilot@users.noreply.github.com> | 2026-02-28 23:32:50 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-28 23:32:50 +0100 |
| commit | 3573ecae94aa328591d4b3a6e2d05e4fc9e261fc (patch) | |
| tree | 1b4484e6d8be40729d5fba473bb2a5309a825434 /src/Enmarcha.Backend/Services/FeedService.cs | |
| parent | a0639ec35054f8b430a3d5aefff734f2f23c9f21 (diff) | |
Deduplicate and collapse routes with excessive short-name variants on stop arrivals (#137)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: arielcostas <94913521+arielcostas@users.noreply.github.com>
Diffstat (limited to 'src/Enmarcha.Backend/Services/FeedService.cs')
| -rw-r--r-- | src/Enmarcha.Backend/Services/FeedService.cs | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/Enmarcha.Backend/Services/FeedService.cs b/src/Enmarcha.Backend/Services/FeedService.cs index 8b0d3e7..b7496ec 100644 --- a/src/Enmarcha.Backend/Services/FeedService.cs +++ b/src/Enmarcha.Backend/Services/FeedService.cs @@ -94,6 +94,59 @@ public class FeedService return NormalizeRouteShortName(feedId, shortName); } + /// <summary> + /// When 5 or more distinct routes share the same 3-character short-name prefix, + /// they are collapsed into a single entry showing "XG{prefix}" (xunta feed only). + /// </summary> + private const int RouteCollapseThreshold = 5; + + /// <summary> + /// Deduplicates routes by <see cref="RouteInfo.ShortName"/> (always). For the xunta feed only, + /// also collapses groups of <see cref="RouteCollapseThreshold"/> or more routes that share the + /// same 3-character prefix into a single entry named "XG{prefix}" (e.g. "XG621"). + /// Other feeds are returned deduplicated but otherwise unchanged. + /// </summary> + public List<RouteInfo> ConsolidateRoutes(string feedId, IEnumerable<RouteInfo> routes) + { + // Deduplicate by short name (case-insensitive) + var deduplicated = routes + .GroupBy(r => r.ShortName, StringComparer.OrdinalIgnoreCase) + .Select(g => g.First()) + .ToList(); + + // Prefix collapsing only applies to xunta routes, which can have dozens of + // sub-routes per contract that would otherwise flood the badge list. + if (feedId != "xunta") + { + return deduplicated; + } + + // Group by the first 3 characters; collapse groups meeting the threshold. + // When collapsing, the first entry's colour is used — routes in the same prefix + // group (e.g. all xunta "621.*" lines) share the same operator colour. + var result = new List<RouteInfo>(); + foreach (var group in deduplicated.GroupBy(r => r.ShortName.Length >= 3 ? r.ShortName[..3] : r.ShortName)) + { + var items = group.ToList(); + if (items.Count >= RouteCollapseThreshold) + { + result.Add(new RouteInfo + { + GtfsId = items[0].GtfsId, + ShortName = $"XG{group.Key}", + Colour = items[0].Colour, + TextColour = items[0].TextColour + }); + } + else + { + result.AddRange(items); + } + } + + return result; + } + public string NormalizeStopName(string feedId, string name) { if (feedId == "vitrasa") |
