Skip to content

Commit f73fcc6

Browse files
symbiogenesisEdward Miller
andauthored
More IndexOf() optimization (#20083)
* Use better IndexOf where possible * apply similar performance improvement to the predicate-based IndexOf() * use built-in IndexOfChild on Android * add braces as per new editorconfig rule * use TryGetValue to avoid double lookup --------- Co-authored-by: Edward Miller <[email protected]>
1 parent 4cfdc90 commit f73fcc6

File tree

6 files changed

+77
-89
lines changed

6 files changed

+77
-89
lines changed

src/Compatibility/ControlGallery/src/Core/GalleryPages/GroupedListContactsGallery.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -200,25 +200,11 @@ void AddContact(ObservableCollection<Group> contactGroups, Contact contact)
200200
InsertBasedOnSort(collection, contact, c => GetSortString(c)[0]);
201201
}
202202

203-
int IndexOf<T>(IEnumerable<T> elements, T element)
204-
{
205-
int i = 0;
206-
foreach (T e in elements)
207-
{
208-
if (Equals(e, element))
209-
return i;
210-
211-
i++;
212-
}
213-
214-
return -1;
215-
}
216-
217203
void InsertBasedOnSort<T, TSort>(IList<T> items, T item, Func<T, TSort> sortBy)
218204
{
219205
List<T> newItems = new List<T>(items);
220206
newItems.Add(item);
221-
int index = IndexOf(newItems.OrderBy(sortBy), item);
207+
int index = newItems.OrderBy(sortBy).IndexOf(item);
222208
items.Insert(index, item);
223209
}
224210

src/Compatibility/Core/src/Android/CollectionView/ObservableItemsSource.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ void Move(NotifyCollectionChangedEventArgs args)
137137

138138
void Add(NotifyCollectionChangedEventArgs args)
139139
{
140-
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]);
140+
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]);
141141
startIndex = AdjustPositionForHeader(startIndex);
142142
var count = args.NewItems.Count;
143143

@@ -178,7 +178,7 @@ void Remove(NotifyCollectionChangedEventArgs args)
178178

179179
void Replace(NotifyCollectionChangedEventArgs args)
180180
{
181-
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]);
181+
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]);
182182
startIndex = AdjustPositionForHeader(startIndex);
183183
var newCount = args.NewItems.Count;
184184

@@ -229,21 +229,5 @@ internal object ElementAt(int index)
229229

230230
return -1;
231231
}
232-
233-
internal int IndexOf(object item)
234-
{
235-
if (_itemsSource is IList list)
236-
return list.IndexOf(item);
237-
238-
int count = 0;
239-
foreach (var i in _itemsSource)
240-
{
241-
if (i == item)
242-
return count;
243-
count++;
244-
}
245-
246-
return -1;
247-
}
248232
}
249233
}

src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void Add(NotifyCollectionChangedEventArgs args)
154154
{
155155
var count = args.NewItems.Count;
156156
Count += count;
157-
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]);
157+
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]);
158158

159159
// Queue up the updates to the UICollectionView
160160
Update(() => CollectionView.InsertItems(CreateIndexesFrom(startIndex, count)), args);
@@ -185,7 +185,7 @@ void Replace(NotifyCollectionChangedEventArgs args)
185185

186186
if (newCount == args.OldItems.Count)
187187
{
188-
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]);
188+
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]);
189189

190190
// We are replacing one set of items with a set of equal size; we can do a simple item range update
191191

@@ -245,22 +245,6 @@ internal object ElementAt(int index)
245245
return -1;
246246
}
247247

248-
internal int IndexOf(object item)
249-
{
250-
if (_itemsSource is IList list)
251-
return list.IndexOf(item);
252-
253-
int count = 0;
254-
foreach (var i in _itemsSource)
255-
{
256-
if (i == item)
257-
return count;
258-
count++;
259-
}
260-
261-
return -1;
262-
}
263-
264248
void Update(Action update, NotifyCollectionChangedEventArgs args)
265249
{
266250
if (CollectionView.Hidden)

src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ObservableItemsSource.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ void Move(NotifyCollectionChangedEventArgs args)
149149

150150
void Add(NotifyCollectionChangedEventArgs args)
151151
{
152-
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]);
152+
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]);
153153
startIndex = AdjustPositionForHeader(startIndex);
154154
var count = args.NewItems.Count;
155155

@@ -190,7 +190,7 @@ void Remove(NotifyCollectionChangedEventArgs args)
190190

191191
void Replace(NotifyCollectionChangedEventArgs args)
192192
{
193-
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]);
193+
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]);
194194
startIndex = AdjustPositionForHeader(startIndex);
195195
var newCount = args.NewItems.Count;
196196

@@ -241,21 +241,5 @@ internal object ElementAt(int index)
241241

242242
return -1;
243243
}
244-
245-
internal int IndexOf(object item)
246-
{
247-
if (_itemsSource is IList list)
248-
return list.IndexOf(item);
249-
250-
int count = 0;
251-
foreach (var i in _itemsSource)
252-
{
253-
if (i == item)
254-
return count;
255-
count++;
256-
}
257-
258-
return -1;
259-
}
260244
}
261245
}

src/Core/src/Extensions/EnumerableExtensions.cs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34

45
namespace Microsoft.Maui
@@ -39,10 +40,14 @@ public static IDictionary<TKey, List<TSource>> GroupToDictionary<TSource, TKey>(
3940
foreach (TSource item in enumeration)
4041
{
4142
var group = func(item);
42-
if (!result.ContainsKey(group))
43+
if (!result.TryGetValue(group, out List<TSource>? value))
44+
{
4345
result.Add(group, new List<TSource> { item });
46+
}
4447
else
45-
result[group].Add(item);
48+
{
49+
value.Add(item);
50+
}
4651
}
4752
return result;
4853
}
@@ -58,19 +63,65 @@ public static IDictionary<TKey, List<TSource>> GroupToDictionary<TSource, TKey>(
5863
public static int IndexOf<T>(this IEnumerable<T> enumerable, T item)
5964
{
6065
if (enumerable == null)
66+
{
6167
throw new ArgumentNullException(nameof(enumerable));
68+
}
6269

63-
if (enumerable is IList<T> list)
64-
return list.IndexOf(item);
70+
if (enumerable is IList<T> list)
71+
{
72+
return list.IndexOf(item);
73+
}
6574

66-
if (enumerable is T[] array)
67-
return Array.IndexOf(array, item);
75+
if (enumerable is T[] array)
76+
{
77+
return Array.IndexOf(array, item);
78+
}
6879

6980
var i = 0;
7081
foreach (T element in enumerable)
7182
{
7283
if (Equals(element, item))
84+
{
85+
return i;
86+
}
87+
88+
i++;
89+
}
90+
91+
return -1;
92+
}
93+
94+
/// <summary>
95+
/// Find the index of a specific item within the collection.
96+
/// </summary>
97+
/// <param name="enumerable">The collection in which to look for <paramref name="item"/>.</param>
98+
/// <param name="item">The object to be located in this collection.</param>
99+
/// <returns>The index of <paramref name="item"/> in the collection or -1 when the item is not found.</returns>
100+
/// <exception cref="ArgumentNullException">Throws when <paramref name="enumerable"/> is <see langword="null"/>.</exception>
101+
public static int IndexOf(this IEnumerable enumerable, object item)
102+
{
103+
if (enumerable == null)
104+
{
105+
throw new ArgumentNullException(nameof(enumerable));
106+
}
107+
108+
if (enumerable is IList list)
109+
{
110+
return list.IndexOf(item);
111+
}
112+
113+
if (enumerable is Array array)
114+
{
115+
return Array.IndexOf(array, item);
116+
}
117+
118+
var i = 0;
119+
foreach (object element in enumerable)
120+
{
121+
if (Equals(element, item))
122+
{
73123
return i;
124+
}
74125

75126
i++;
76127
}
@@ -91,11 +142,23 @@ public static int IndexOf<T>(this IEnumerable<T> enumerable, T item)
91142
[Obsolete("Use IndexOf<T>(IEnumerable<T>, T item) instead.")]
92143
public static int IndexOf<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
93144
{
145+
if (enumerable == null)
146+
{
147+
throw new ArgumentNullException(nameof(enumerable));
148+
}
149+
150+
if (enumerable is IList<T> list)
151+
{
152+
return list.IndexOf(predicate);
153+
}
154+
94155
var i = 0;
95156
foreach (T element in enumerable)
96157
{
97158
if (predicate(element))
159+
{
98160
return i;
161+
}
99162

100163
i++;
101164
}

src/Core/src/Handlers/Layout/LayoutHandler.Android.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ void EnsureZIndexOrder(IView child)
119119
}
120120

121121
AView platformChildView = child.ToPlatform(MauiContext!);
122-
var currentIndex = IndexOf(PlatformView, platformChildView);
122+
var currentIndex = PlatformView.IndexOfChild(platformChildView);
123123

124124
if (currentIndex == -1)
125125
{
@@ -135,19 +135,6 @@ void EnsureZIndexOrder(IView child)
135135
}
136136
}
137137

138-
static int IndexOf(LayoutViewGroup viewGroup, AView view)
139-
{
140-
for (int n = 0; n < viewGroup.ChildCount; n++)
141-
{
142-
if (viewGroup.GetChildAt(n) == view)
143-
{
144-
return n;
145-
}
146-
}
147-
148-
return -1;
149-
}
150-
151138
public static partial void MapBackground(ILayoutHandler handler, ILayout layout)
152139
{
153140
handler.PlatformView?.UpdateBackground(layout);

0 commit comments

Comments
 (0)