From 0ed803f26035b739dc59556b9a9c6dedc3852e98 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Mon, 22 Jan 2024 14:26:12 -0600 Subject: [PATCH 1/5] Use better IndexOf where possible --- .../GroupedListContactsGallery.cs | 16 +--------- .../CollectionView/ObservableItemsSource.cs | 20 ++---------- .../CollectionView/ObservableItemsSource.cs | 20 ++---------- .../ItemsSources/ObservableItemsSource.cs | 20 ++---------- .../src/Extensions/EnumerableExtensions.cs | 31 +++++++++++++++++++ 5 files changed, 38 insertions(+), 69 deletions(-) diff --git a/src/Compatibility/ControlGallery/src/Core/GalleryPages/GroupedListContactsGallery.cs b/src/Compatibility/ControlGallery/src/Core/GalleryPages/GroupedListContactsGallery.cs index f33a3de14eab..0b009adf2da9 100644 --- a/src/Compatibility/ControlGallery/src/Core/GalleryPages/GroupedListContactsGallery.cs +++ b/src/Compatibility/ControlGallery/src/Core/GalleryPages/GroupedListContactsGallery.cs @@ -200,25 +200,11 @@ void AddContact(ObservableCollection contactGroups, Contact contact) InsertBasedOnSort(collection, contact, c => GetSortString(c)[0]); } - int IndexOf(IEnumerable elements, T element) - { - int i = 0; - foreach (T e in elements) - { - if (Equals(e, element)) - return i; - - i++; - } - - return -1; - } - void InsertBasedOnSort(IList items, T item, Func sortBy) { List newItems = new List(items); newItems.Add(item); - int index = IndexOf(newItems.OrderBy(sortBy), item); + int index = newItems.OrderBy(sortBy).IndexOf(item); items.Insert(index, item); } diff --git a/src/Compatibility/Core/src/Android/CollectionView/ObservableItemsSource.cs b/src/Compatibility/Core/src/Android/CollectionView/ObservableItemsSource.cs index eb68661752ff..9ca19ac3e8cb 100644 --- a/src/Compatibility/Core/src/Android/CollectionView/ObservableItemsSource.cs +++ b/src/Compatibility/Core/src/Android/CollectionView/ObservableItemsSource.cs @@ -137,7 +137,7 @@ void Move(NotifyCollectionChangedEventArgs args) void Add(NotifyCollectionChangedEventArgs args) { - var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]); + var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]); startIndex = AdjustPositionForHeader(startIndex); var count = args.NewItems.Count; @@ -178,7 +178,7 @@ void Remove(NotifyCollectionChangedEventArgs args) void Replace(NotifyCollectionChangedEventArgs args) { - var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]); + var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]); startIndex = AdjustPositionForHeader(startIndex); var newCount = args.NewItems.Count; @@ -229,21 +229,5 @@ internal object ElementAt(int index) return -1; } - - internal int IndexOf(object item) - { - if (_itemsSource is IList list) - return list.IndexOf(item); - - int count = 0; - foreach (var i in _itemsSource) - { - if (i == item) - return count; - count++; - } - - return -1; - } } } diff --git a/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs b/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs index f67f1d3ca9c1..c18e0e5e44a8 100644 --- a/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs +++ b/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs @@ -154,7 +154,7 @@ void Add(NotifyCollectionChangedEventArgs args) { var count = args.NewItems.Count; Count += count; - var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]); + var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]); // Queue up the updates to the UICollectionView Update(() => CollectionView.InsertItems(CreateIndexesFrom(startIndex, count)), args); @@ -185,7 +185,7 @@ void Replace(NotifyCollectionChangedEventArgs args) if (newCount == args.OldItems.Count) { - var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]); + var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]); // We are replacing one set of items with a set of equal size; we can do a simple item range update @@ -245,22 +245,6 @@ internal object ElementAt(int index) return -1; } - internal int IndexOf(object item) - { - if (_itemsSource is IList list) - return list.IndexOf(item); - - int count = 0; - foreach (var i in _itemsSource) - { - if (i == item) - return count; - count++; - } - - return -1; - } - void Update(Action update, NotifyCollectionChangedEventArgs args) { if (CollectionView.Hidden) diff --git a/src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ObservableItemsSource.cs b/src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ObservableItemsSource.cs index dbd0987bfca7..40c57c83eed1 100644 --- a/src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ObservableItemsSource.cs +++ b/src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ObservableItemsSource.cs @@ -149,7 +149,7 @@ void Move(NotifyCollectionChangedEventArgs args) void Add(NotifyCollectionChangedEventArgs args) { - var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]); + var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]); startIndex = AdjustPositionForHeader(startIndex); var count = args.NewItems.Count; @@ -190,7 +190,7 @@ void Remove(NotifyCollectionChangedEventArgs args) void Replace(NotifyCollectionChangedEventArgs args) { - var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]); + var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]); startIndex = AdjustPositionForHeader(startIndex); var newCount = args.NewItems.Count; @@ -241,21 +241,5 @@ internal object ElementAt(int index) return -1; } - - internal int IndexOf(object item) - { - if (_itemsSource is IList list) - return list.IndexOf(item); - - int count = 0; - foreach (var i in _itemsSource) - { - if (i == item) - return count; - count++; - } - - return -1; - } } } diff --git a/src/Core/src/Extensions/EnumerableExtensions.cs b/src/Core/src/Extensions/EnumerableExtensions.cs index fb1fef33d8c0..955efff9cb22 100644 --- a/src/Core/src/Extensions/EnumerableExtensions.cs +++ b/src/Core/src/Extensions/EnumerableExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; namespace Microsoft.Maui @@ -74,6 +75,36 @@ public static int IndexOf(this IEnumerable enumerable, T item) return -1; } + /// + /// Find the index of a specific item within the collection. + /// + /// The collection in which to look for . + /// The object to be located in this collection. + /// The index of in the collection or -1 when the item is not found. + /// Throws when is . + public static int IndexOf(this IEnumerable enumerable, object item) + { + if (enumerable == null) + throw new ArgumentNullException(nameof(enumerable)); + + if (enumerable is IList list) + return list.IndexOf(item); + + if (enumerable is Array array) + return Array.IndexOf(array, item); + + var i = 0; + foreach (object element in enumerable) + { + if (Equals(element, item)) + return i; + + i++; + } + + return -1; + } + /// /// Find the index for the first occurrence of an item within the collection as matched through the specified predicate. /// From 8f2739c9dcfc4da6d18e7ab24199cc747f0f9eb1 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Mon, 22 Jan 2024 14:26:17 -0600 Subject: [PATCH 2/5] apply similar performance improvement to the predicate-based IndexOf() --- src/Core/src/Extensions/EnumerableExtensions.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Core/src/Extensions/EnumerableExtensions.cs b/src/Core/src/Extensions/EnumerableExtensions.cs index 955efff9cb22..4048ec9fcc4b 100644 --- a/src/Core/src/Extensions/EnumerableExtensions.cs +++ b/src/Core/src/Extensions/EnumerableExtensions.cs @@ -116,6 +116,12 @@ public static int IndexOf(this IEnumerable enumerable, object item) /// The index of the first item to match through in the collection or -1 when no match is not found. public static int IndexOf(this IEnumerable enumerable, Func predicate) { + if (enumerable == null) + throw new ArgumentNullException(nameof(enumerable)); + + if (enumerable is IList list) + return list.IndexOf(predicate); + var i = 0; foreach (T element in enumerable) { From 16e39a42866f05071d82e66d6e148b9deb2eb175 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Mon, 22 Jan 2024 15:24:39 -0600 Subject: [PATCH 3/5] use built-in IndexOfChild on Android --- .../src/Handlers/Layout/LayoutHandler.Android.cs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs index 1934477a27c7..eb0df4eca87b 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs @@ -119,7 +119,7 @@ void EnsureZIndexOrder(IView child) } AView platformChildView = child.ToPlatform(MauiContext!); - var currentIndex = IndexOf(PlatformView, platformChildView); + var currentIndex = PlatformView.IndexOfChild(platformChildView); if (currentIndex == -1) { @@ -135,19 +135,6 @@ void EnsureZIndexOrder(IView child) } } - static int IndexOf(LayoutViewGroup viewGroup, AView view) - { - for (int n = 0; n < viewGroup.ChildCount; n++) - { - if (viewGroup.GetChildAt(n) == view) - { - return n; - } - } - - return -1; - } - public static partial void MapBackground(ILayoutHandler handler, ILayout layout) { handler.PlatformView?.UpdateBackground(layout); From 9d6afc28e96ab6156b097ac39909662c321f4f71 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Mon, 22 Jan 2024 19:57:52 -0600 Subject: [PATCH 4/5] add braces as per new editorconfig rule --- .../src/Extensions/EnumerableExtensions.cs | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Core/src/Extensions/EnumerableExtensions.cs b/src/Core/src/Extensions/EnumerableExtensions.cs index 4048ec9fcc4b..eb37d23d3173 100644 --- a/src/Core/src/Extensions/EnumerableExtensions.cs +++ b/src/Core/src/Extensions/EnumerableExtensions.cs @@ -37,9 +37,13 @@ public static IDictionary> GroupToDictionary( { var group = func(item); if (!result.ContainsKey(group)) + { result.Add(group, new List { item }); + } else + { result[group].Add(item); + } } return result; } @@ -55,19 +59,27 @@ public static IDictionary> GroupToDictionary( public static int IndexOf(this IEnumerable enumerable, T item) { if (enumerable == null) + { throw new ArgumentNullException(nameof(enumerable)); + } - if (enumerable is IList list) - return list.IndexOf(item); + if (enumerable is IList list) + { + return list.IndexOf(item); + } - if (enumerable is T[] array) - return Array.IndexOf(array, item); + if (enumerable is T[] array) + { + return Array.IndexOf(array, item); + } var i = 0; foreach (T element in enumerable) { if (Equals(element, item)) + { return i; + } i++; } @@ -85,19 +97,27 @@ public static int IndexOf(this IEnumerable enumerable, T item) public static int IndexOf(this IEnumerable enumerable, object item) { if (enumerable == null) + { throw new ArgumentNullException(nameof(enumerable)); + } - if (enumerable is IList list) - return list.IndexOf(item); + if (enumerable is IList list) + { + return list.IndexOf(item); + } - if (enumerable is Array array) - return Array.IndexOf(array, item); + if (enumerable is Array array) + { + return Array.IndexOf(array, item); + } var i = 0; foreach (object element in enumerable) { if (Equals(element, item)) + { return i; + } i++; } @@ -117,16 +137,22 @@ public static int IndexOf(this IEnumerable enumerable, object item) public static int IndexOf(this IEnumerable enumerable, Func predicate) { if (enumerable == null) + { throw new ArgumentNullException(nameof(enumerable)); + } - if (enumerable is IList list) - return list.IndexOf(predicate); + if (enumerable is IList list) + { + return list.IndexOf(predicate); + } var i = 0; foreach (T element in enumerable) { if (predicate(element)) + { return i; + } i++; } From 1f8fca435c2afee04de7ce4dda87028d00f20bad Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Mon, 22 Jan 2024 19:59:35 -0600 Subject: [PATCH 5/5] use TryGetValue to avoid double lookup --- src/Core/src/Extensions/EnumerableExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Extensions/EnumerableExtensions.cs b/src/Core/src/Extensions/EnumerableExtensions.cs index eb37d23d3173..44ca3f7ffa58 100644 --- a/src/Core/src/Extensions/EnumerableExtensions.cs +++ b/src/Core/src/Extensions/EnumerableExtensions.cs @@ -36,13 +36,13 @@ public static IDictionary> GroupToDictionary( foreach (TSource item in enumeration) { var group = func(item); - if (!result.ContainsKey(group)) + if (!result.TryGetValue(group, out List? value)) { result.Add(group, new List { item }); } else { - result[group].Add(item); + value.Add(item); } } return result;