-
Notifications
You must be signed in to change notification settings - Fork 421
Description
I'd like to suggest adding an operator that will return items of a sequence at given sequence of zero-based positions or indices. It will traverse the source items and an indices sequence in order and return the items at the corresponding indices. Duplicate indices are allowed. For most optimal (unbuffered) operation, indices would be given in increasing order.
The signature would be as follows:
public static IEnumerable<TResult>
BindByIndex<T, TResult>(this IEnumerable<T> source, IEnumerable<int> indices,
int lookBackSize,
Func<int, TResult> missingSelector,
Func<T, int, TResult> resultSelector)
Simpler overloads could be added.
If indices
are in ascending order then lookBackSize
is immaterial. If indices
are unordered then lookBackSize
will be the size of an internal scrolling buffer of source items that enables looking back.
The missingSelector
argument allows projection of a result item when an index is not found, such as when it is less than zero or greater or equal to the number of items in source
.
Suppose the following:
var xs = new[] { "foo", "bar", "baz", "qux" };
var result = xs.BindByIndex(indices, lookBackSize, i => "?", (s, _) => s);
The table below shows what result
will contain for given inputs of indices
and lookBackSize
:
# | indices |
lookBackSize |
result |
---|---|---|---|
1 | [2, 3] | 0 | [baz, qux] |
2 | [1, 3] | 0 | [bar, qux] |
3 | [0, 2, 3] | 0 | [foo, baz, qux] |
4 | [0, 2, 3] | 0 | [foo, baz, qux] |
5 | [0, 1, 1] | 0 | [foo, bar, bar] |
6 | [3, 1, 2] | 0 | [qux, ?, ?] |
7 | [3, 1, 2] | 4 | [qux, bar, baz] |
8 | [3, 1, 2] | 1 | [qux, ?, baz] |
9 | [-1, 1, 2, 10] | 0 | [?, bar, baz, ?] |
Things to note:
- In example 5, indexing and returning duplicate items is supported.
- In example 6, items for indices 1 and 2 are missed because look-back is not possible after 3 (
lookBackSize
is 0) but example 7 fixes that. - In example 8, the item for index is missed since
lookBackSize
is 1 and so a look-back that far from index 3 is no longer possible.
Example
const string csv = @"
# Generated using https://mockaroo.com/
id,first_name,last_name,email,gender,ip_address
1,Maggee,Hould,[email protected],Female,158.221.234.250
2,Judas,Vedekhov,[email protected],Male,26.25.8.252
3,Sharity,Desquesnes,[email protected],Female,27.224.140.230
4,Della,Conant,[email protected],Female,229.74.161.94
5,Sansone,Hardson,[email protected],Male,51.154.224.38
6,Lloyd,Cromley,[email protected],Male,168.145.20.63
7,Ty,Bamsey,[email protected],Male,129.204.46.174
8,Hurlee,Dumphy,[email protected],Male,95.17.55.115
9,Andy,Vickarman,[email protected],Male,10.159.118.60
10,Jerad,Kerley,[email protected],Male,3.19.136.57
";
// Parse CSV into rows of fields with commented lines,
// those starting with pound or hash (#), removed.
var rows =
from row in Regex.Split(csv.Trim(), "\r?\n")
select row.Trim() into row
where row.Length > 0 && row[0] != '#'
select row.Trim().Split(',');
// Split header and data rows
var (header, data) =
rows.Index()
.Partition(e => e.Key == 0,
(hr, dr) => (hr.Single().Value, from e in dr select e.Value));
// Locate indices of headers
var bindings = Enumerable.ToArray(
from h in new[] { "id", "email", "last_name", "first_name", "foo" }
select Array.FindIndex(header, sh => sh == h));
// Bind to data using
var objects =
from row in data
select row.BindByIndex(bindings, bindings.Length, i => null, (f, _) => f)
.Fold((id, email, ln, fn, foo) => new
{
Id = int.Parse(id),
FirstName = fn,
LastName = ln,
Email = new MailAddress(email),
Foo = foo,
});
foreach (var obj in objects)
Console.WriteLine(obj.ToString());
Output
{ Id = 1, FirstName = Maggee, LastName = Hould, Email = [email protected], Foo = }
{ Id = 2, FirstName = Judas, LastName = Vedekhov, Email = [email protected], Foo = }
{ Id = 3, FirstName = Sharity, LastName = Desquesnes, Email = [email protected], Foo = }
{ Id = 4, FirstName = Della, LastName = Conant, Email = [email protected], Foo = }
{ Id = 5, FirstName = Sansone, LastName = Hardson, Email = [email protected], Foo = }
{ Id = 6, FirstName = Lloyd, LastName = Cromley, Email = [email protected], Foo = }
{ Id = 7, FirstName = Ty, LastName = Bamsey, Email = [email protected], Foo = }
{ Id = 8, FirstName = Hurlee, LastName = Dumphy, Email = [email protected], Foo = }
{ Id = 9, FirstName = Andy, LastName = Vickarman, Email = [email protected], Foo = }
{ Id = 10, FirstName = Jerad, LastName = Kerley, Email = [email protected], Foo = }