Skip to content

Commit ce4dda4

Browse files
committed
Use an index lookup for O(1) field index access
1 parent 45b3697 commit ce4dda4

File tree

2 files changed

+77
-11
lines changed

2 files changed

+77
-11
lines changed

csharp/src/Apache.Arrow/Schema.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public partial class Schema : IRecordType
3131
private readonly List<Field> _fieldsList;
3232

3333
public ILookup<string, Field> FieldsLookup { get; }
34+
private readonly ILookup<string, int> _fieldsIndexLookup;
3435

3536
public IReadOnlyDictionary<string, string> Metadata { get; }
3637

@@ -43,17 +44,11 @@ public partial class Schema : IRecordType
4344
public Schema(
4445
IEnumerable<Field> fields,
4546
IEnumerable<KeyValuePair<string, string>> metadata)
47+
: this(
48+
fields.ToList(),
49+
metadata?.ToDictionary(kv => kv.Key, kv => kv.Value),
50+
false)
4651
{
47-
if (fields is null)
48-
{
49-
throw new ArgumentNullException(nameof(fields));
50-
}
51-
52-
_fieldsList = fields.ToList();
53-
FieldsLookup = _fieldsList.ToLookup(f => f.Name);
54-
_fieldsDictionary = FieldsLookup.ToDictionary(g => g.Key, g => g.First());
55-
56-
Metadata = metadata?.ToDictionary(kv => kv.Key, kv => kv.Value);
5752
}
5853

5954
internal Schema(List<Field> fieldsList, IReadOnlyDictionary<string, string> metadata, bool copyCollections)
@@ -66,6 +61,10 @@ internal Schema(List<Field> fieldsList, IReadOnlyDictionary<string, string> meta
6661
_fieldsDictionary = FieldsLookup.ToDictionary(g => g.Key, g => g.First());
6762

6863
Metadata = metadata;
64+
65+
_fieldsIndexLookup = _fieldsList
66+
.Select((x, idx) => (Name: x.Name, Index: idx))
67+
.ToLookup(x => x.Name, x => x.Index, StringComparer.CurrentCulture);
6968
}
7069

7170
public Field GetFieldByIndex(int i) => _fieldsList[i];
@@ -80,7 +79,10 @@ public int GetFieldIndex(string name, StringComparer comparer)
8079

8180
public int GetFieldIndex(string name, IEqualityComparer<string> comparer = default)
8281
{
83-
comparer ??= StringComparer.CurrentCulture;
82+
if (comparer == null)
83+
{
84+
return _fieldsIndexLookup[name].First();
85+
}
8486

8587
return _fieldsList.IndexOf(_fieldsList.First(x => comparer.Equals(x.Name, name)));
8688
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
// Licensed to the Apache Software Foundation (ASF) under one or more
3+
// contributor license agreements. See the NOTICE file distributed with
4+
// this work for additional information regarding copyright ownership.
5+
// The ASF licenses this file to You under the Apache License, Version 2.0
6+
// (the "License"); you may not use this file except in compliance with
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
using Apache.Arrow;
18+
using Apache.Arrow.Types;
19+
using System;
20+
using Xunit;
21+
22+
namespace Apache.Arrow.Tests;
23+
24+
internal class SchemaTests
25+
{
26+
public class Construct
27+
{
28+
[Fact]
29+
public void ThrowsWhenFieldsAreNull()
30+
{
31+
Assert.Throws<ArgumentNullException>(() => new Schema(null, null));
32+
Assert.Throws<ArgumentNullException>(() => new Schema(null, null, copyCollections: false));
33+
}
34+
}
35+
36+
public class IndexRetrieval
37+
{
38+
[Fact]
39+
public void CanRetrieveFieldIndexByName()
40+
{
41+
var field0 = new Field("f0", Int32Type.Default, true);
42+
var field1 = new Field("f1", Int64Type.Default, true);
43+
var schema = new Schema([field0, field1], null);
44+
45+
Assert.Equal(0, schema.GetFieldIndex("f0"));
46+
Assert.Equal(1, schema.GetFieldIndex("f1"));
47+
Assert.Equal(-1, schema.GetFieldIndex("nonexistent"));
48+
}
49+
50+
[Fact]
51+
public void CanRetrieveFieldIndexByNonUniqueName()
52+
{
53+
var field0 = new Field("f0", Int32Type.Default, true);
54+
var field1 = new Field("f1", Int64Type.Default, true);
55+
56+
// Repeat fields in the list
57+
var schema = new Schema([field0, field1, field0, field1], null);
58+
59+
Assert.Equal(0, schema.GetFieldIndex("f0"));
60+
Assert.Equal(1, schema.GetFieldIndex("f1"));
61+
Assert.Equal(-1, schema.GetFieldIndex("nonexistent"));
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)