From c8d3dd0e5a62e126eb9e2d7701aec7e731a5effb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 27 Oct 2019 23:14:14 +0100 Subject: [PATCH] Make carousel item sorting stable Migrate beatmap carousel item sorting from List.Sort() to IEnumerable.OrderBy(), as the second variant is documented to be a stable sorting algorithm. This allows for eliminating unnecessary movement of carousel items occurring whenever any set of items is tied when changing sorting criteria. --- .../Screens/Select/Carousel/CarouselGroup.cs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs index 09b728abeb..b32561eb88 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; +using System.Linq; namespace osu.Game.Screens.Select.Carousel { @@ -81,12 +83,9 @@ namespace osu.Game.Screens.Select.Carousel { base.Filter(criteria); - var children = new List(InternalChildren); - - children.ForEach(c => c.Filter(criteria)); - children.Sort((x, y) => x.CompareTo(criteria, y)); - - InternalChildren = children; + InternalChildren.ForEach(c => c.Filter(criteria)); + // IEnumerable.OrderBy() is used instead of List.Sort() to ensure sorting stability + InternalChildren = InternalChildren.OrderBy(c => c, new CriteriaComparer(criteria)).ToList(); } protected virtual void ChildItemStateChanged(CarouselItem item, CarouselItemState value) @@ -104,5 +103,23 @@ namespace osu.Game.Screens.Select.Carousel State.Value = CarouselItemState.Selected; } } + + private class CriteriaComparer : IComparer + { + private readonly FilterCriteria criteria; + + public CriteriaComparer(FilterCriteria criteria) + { + this.criteria = criteria; + } + + public int Compare(CarouselItem x, CarouselItem y) + { + if (x != null && y != null) + return x.CompareTo(criteria, y); + + throw new ArgumentNullException(); + } + } } }