FunVec2T Class

A unified functional 2-dimensional collection. It does not hold the data, rather provides a unified view over different sources of data providing indexed access to collection elements.

Takes a functional approach; i.e., the following closures are defined and stored on construction:

  • closure to get the jagged lengths in all dimensions;
  • closure to get element at the given indices (also the bounds-checked version GetOrNone, in addition to direct access by indices);
  • closure to get the collection as IEnumerable.
The allocation is limited by these closures. The data is not re-allocated, or memoized.

For instance, if a unified collection is defined to always return a contant value, and have a length of 1000 collections in the first dimension, and 1000 elements in the second dimension for each of the collection; there will NOT be an underlying array storing the same value 1_000_000 times.

To clarify that the unified collection only holds a reference, consider the following example.

C#
int[][] underlyingArray = new int[] { new int[] { 0, 10 }, new int[] { 1, 11, 111, 1111 }, new int[] { 2, 22, 222 } };
FunVec2<int> jagged = new(underlyingArray);
Assert(underlyingArray[1][0] == 1 and jagged[1, 0] == 1);
underlyingArray[1][0] = 42;
Assert(underlyingArray[1][0] == 42 and jagged[1, 0] == 42);

To further illustrate, consider the following with underlying list of lists.

C#
List<List<char>> underlyingList = new() { new() { 'a', 'b', 'c', 'd' }, new() { 'u', 'v' } };
FunVec2<char> jagged = new(underlyingList);

Assert(underlyingList.Count == 2 and jagged.Length1 == 2);
underlyingList.Add(new() { 'x', 'y', 'z' });
Assert(underlyingList.Count == 3 and jagged.Length1 == 3);

Assert(underlyingList[0].Count == 4 and jagged.Length2(0) == 4);
underlyingList[0].Add('e');
Assert(underlyingList[0].Count == 5 and jagged.Length2(0) == 5);

The unified jagged collection exposes a unified interface for the following methods:

  • Length1: length in the first dimension (i.e., number of 1D collections).
  • Length2(i): length of the i-th collection in the second dimension (i.e., number of elements in the i-th 1D collection).
  • this[i]: i-th D1 collection.
  • this[i,j]: element at the (i,j)-th position (i.e., j-th element of the i-th 1D collection).
  • GetOrNone(i, j): returns Some of the element at the (i,j)-th position if indices are valid; None otherwise.
  • AsEnumerable(): returns the collection as IEnumerable; particularly useful for linq calls over the collection.

Definition

Namespace: Orx.Fun.FunVec
Assembly: Orx.Fun.FunVec (in Orx.Fun.FunVec.dll) Version: 1.0.0
C#
public class FunVec2<T> : IEnumerable<FunVec1<T>>, 
	IEnumerable
Inheritance
Object    FunVec2T
Implements
IEnumerableFunVec1T, IEnumerable

Type Parameters

T
Type of the innermost elements of the collection.

Constructors

FunVec2T(T) 2-dimensional jagged collection lengths and values of which are determined by the underlying array.
C#
var array = new char[][] { new char[] { 'a', 'b', 'c' }, new char[] { 'd' } };
FunVec2<char> jagged = new(array);
Assert(jagged.Length1 == 2);
Assert(jagged.Length2(0) == 3);
Assert(jagged.Length2(1) == 1);
Assert(jagged[0, 2] == 'c');
Assert(jagged.GetOrNone(1, 0) == Some('d'));
Assert(jagged.GetOrNone(0, 3).IsNone);
Assert(jagged.GetOrNone(2, 0).IsNone);
FunVec2T(ListListT) 2-dimensional jagged collection lengths and values of which are determined by the underlying list.
C#
var list = new List<List<char>>() { new() { 'a', 'b', 'c' }, new() { 'd' } };
FunVec2<char> jagged = new(list);
Assert(jagged.Length1 == 2);
Assert(jagged.Length2(0) == 3);
Assert(jagged.Length2(1) == 1);
Assert(jagged[0, 2] == 'c');
Assert(jagged.GetOrNone(1, 0) == Some('d'));
Assert(jagged.GetOrNone(0, 3).IsNone);
Assert(jagged.GetOrNone(2, 0).IsNone);
FunVec2T(FuncInt32, Int32, T, OptInt32, OptFuncInt32, Int32) 2-dimensional jagged collection with optional lengths, values of which are determined by the getValue function.
C#
static int GetDistance(int from, int to) { return Math.Abs(to - from); }

FunVec2<int> distances = new(GetDistance);
Assert(distances.Length1 == int.MaxValue);    // since length1 is omitted
Assert(distances.Length2(100) == int.MaxValue); // since length2 is omitted
Assert(distances[1, 2] == 1);
Assert(distances[10, 5] == 5);

FunVec2<int> distancesUpTo4 = new(GetDistance, Some(4));
Assert(distancesUpTo4.Length1 == 4);
Assert(distancesUpTo4[3, 1] == 2);
// Assert(distancesUpTo4[5, 1] == 4); // out-of-bounds, throws!
Assert(distancesUpTo4.GetOrNone(5, 1).IsNone);

FunVec2<int> distancesUpTo4 = new(GetDistance, Some(4), Some<Func<int, int>>(i => 2*i));
Assert(distancesUpTo4.Length1 == 4);
Assert(distancesUpTo4.Length2(2) == 4);
Assert(distancesUpTo4[3, 5] == 2);
// Assert(distancesUpTo4[3, 6] == 3); // out-of-bounds, throws!
// Assert(distancesUpTo4[4, 0] == 4); // out-of-bounds, throws!
Assert(distancesUpTo4.GetOrNone(3, 6).IsNone);  // since Length2(3) is 6, index 6 is out of bounds.
Assert(distancesUpTo4.GetOrNone(4, 0).IsNone);  // since Length1 is 4, index 4 is out of bounds.
FunVec2T(T, OptInt32, OptFuncInt32, Int32) 2-dimensional jagged collection with optional lengths, which always yields the same constant value.
C#
var agentSmith = GetSmith();
FunVec2<Agent> jagged = new(agentSmith);
Assert(jagged.Length1 == int.MaxValue);   // since length1 is omitted
Assert(jagged.Length2(42) == int.MaxValue); // since length2 is omitted
Assert(jagged[0][0] == agentSmith);
Assert(jagged[42][42] == agentSmith);
Assert(jagged.GetOrNone(100, 42) == Some(agentSmith));

FunVec2<Agent> jagged = new(agentSmith, Some(50));
Assert(jagged.Length1 == 50);
Assert(jagged.Length2(42) == int.MaxValue); // since length2 is omitted
Assert(jagged[0][0] == agentSmith);
Assert(jagged[42][142] == agentSmith);
Assert(jagged.GetOrNone(100, 2).IsNone);

FunVec2<Agent> jagged = new(agentSmith, Some(50), Some<Func<int, int>>(_ => 2));
Assert(jagged.Length1 == 50);
Assert(jagged.Length2(42) == 2);
Assert(jagged[0][0] == agentSmith);
Assert(jagged[42][1] == agentSmith);
Assert(jagged.GetOrNone(0, 2).IsNone);
Assert(jagged.GetOrNone(50, 0).IsNone);

FunVec2<Agent> jagged = new(agentSmith, Some(50), Some<Func<int, int>>(i => i));
Assert(jagged.Length1 == 50);
Assert(jagged.Length2(0) == 0);
Assert(jagged.Length2(42) == 42);
Assert(jagged[42][1] == agentSmith);
Assert(jagged.GetOrNone(1, 0) == Some(agentSmith));
Assert(jagged.GetOrNone(0, 0).IsNone);
Assert(jagged.GetOrNone(50, 0).IsNone);

Properties

HasUnderlyingScalar The unified collection might be constructed with a constant scalar value; hence, returning the scalar for all indices. If this is the case, HasUnderlyingScalar is true; and the field UnderlyingScalar equals to Some of the underlying scalar value.

Otherwise, HasUnderlyingScalar is false and UnderlyingScalar.IsNone.

C#
// vec[i] = 10, for all i.
UniJaggedD1<int> vec = new(10);
Assert(vec[3] == 10 and vec[42] == 10);
Assert(vec.Get(12) == Some(10));

// underlying constant can be obtained by the optional UnderlyingScalar field.
Assert(vec.HasUnderlyingScalar);
Assert(vec.UnderlyingScalar.IsSome);
Assert(vec.UnderlyingScalar == Some(10));
Assert(vec.UnderlyingScalar.Unwrap() == 10);
Item Directly returns the element at the i-th position. Use Get(Int32, Int32) for the bound-checked optional version.
C#
var underlyingArray = new int[] { 10, 11, 12 };
FunVec1<int> vec = new(underlyingArray);

Assert(vec[1] == 11);

// var x = vec[-1]; => out-of-bounds, throws!
// var x = vec[3]; => out-of-bounds, throws!

Methods

Equals
(Inherited from Object)
Finalize
(Inherited from Object)
Get Safely gets the element at the i-th position; returns None if the index is invalid.
C#
var underlyingArray = new int[] { 10, 11, 12 };
FunVec1<int> vec = new(underlyingArray);

Assert(jagvecged.Get(1) == Some(11));
Assert(vec.Get(-1).IsNone);
Assert(vec.Get(2).IsNone);
For other methods on the resulting optional, see Opt.
GetEnumerator Returns the enumerator for sub-vectors in the vector.
GetHashCode
(Inherited from Object)
GetType
(Inherited from Object)
MemberwiseClone
(Inherited from Object)
ToString
(Inherited from Object)

Operators

(FuncInt32, Int32, T to FunVec2T) 2-dimensional jagged collection with optional lengths, values of which are determined by the getValue function.
C#
static int GetDistance(int from, int to) { return Math.Abs(to - from); }

FunVec2<int> distances = new(GetDistance);
Assert(distances.Length1 == int.MaxValue);    // since length1 is omitted
Assert(distances.Length2(100) == int.MaxValue); // since length2 is omitted
Assert(distances[1, 2] == 1);
Assert(distances[10, 5] == 5);

FunVec2<int> distancesUpTo4 = new(GetDistance, Some(4));
Assert(distancesUpTo4.Length1 == 4);
Assert(distancesUpTo4[3, 1] == 2);
// Assert(distancesUpTo4[5, 1] == 4); // out-of-bounds, throws!
Assert(distancesUpTo4.GetOrNone(5, 1).IsNone);

FunVec2<int> distancesUpTo4 = new(GetDistance, Some(4), Some<Func<int, int>>(i => 2*i));
Assert(distancesUpTo4.Length1 == 4);
Assert(distancesUpTo4.Length2(2) == 4);
Assert(distancesUpTo4[3, 5] == 2);
// Assert(distancesUpTo4[3, 6] == 3); // out-of-bounds, throws!
// Assert(distancesUpTo4[4, 0] == 4); // out-of-bounds, throws!
Assert(distancesUpTo4.GetOrNone(3, 6).IsNone);  // since Length2(3) is 6, index 6 is out of bounds.
Assert(distancesUpTo4.GetOrNone(4, 0).IsNone);  // since Length1 is 4, index 4 is out of bounds.
(T to FunVec2T) 2-dimensional jagged collection with optional lengths, which always yields the same constant value.
C#
var agentSmith = GetSmith();
FunVec2<Agent> jagged = new(agentSmith);
Assert(jagged.Length1 == int.MaxValue);   // since length1 is omitted
Assert(jagged.Length2(42) == int.MaxValue); // since length2 is omitted
Assert(jagged[0][0] == agentSmith);
Assert(jagged[42][42] == agentSmith);
Assert(jagged.GetOrNone(100, 42) == Some(agentSmith));

FunVec2<Agent> jagged = new(agentSmith, Some(50));
Assert(jagged.Length1 == 50);
Assert(jagged.Length2(42) == int.MaxValue); // since length2 is omitted
Assert(jagged[0][0] == agentSmith);
Assert(jagged[42][142] == agentSmith);
Assert(jagged.GetOrNone(100, 2).IsNone);

FunVec2<Agent> jagged = new(agentSmith, Some(50), Some<Func<int, int>>(_ => 2));
Assert(jagged.Length1 == 50);
Assert(jagged.Length2(42) == 2);
Assert(jagged[0][0] == agentSmith);
Assert(jagged[42][1] == agentSmith);
Assert(jagged.GetOrNone(0, 2).IsNone);
Assert(jagged.GetOrNone(50, 0).IsNone);

FunVec2<Agent> jagged = new(agentSmith, Some(50), Some<Func<int, int>>(i => i));
Assert(jagged.Length1 == 50);
Assert(jagged.Length2(0) == 0);
Assert(jagged.Length2(42) == 42);
Assert(jagged[42][1] == agentSmith);
Assert(jagged.GetOrNone(1, 0) == Some(agentSmith));
Assert(jagged.GetOrNone(0, 0).IsNone);
Assert(jagged.GetOrNone(50, 0).IsNone);
(T to FunVec2T) 2-dimensional jagged collection lengths and values of which are determined by the underlying array.
C#
var array = new char[][] { new char[] { 'a', 'b', 'c' }, new char[] { 'd' } };
FunVec2<char> jagged = new(array);
Assert(jagged.Length1 == 2);
Assert(jagged.Length2(0) == 3);
Assert(jagged.Length2(1) == 1);
Assert(jagged[0, 2] == 'c');
Assert(jagged.GetOrNone(1, 0) == Some('d'));
Assert(jagged.GetOrNone(0, 3).IsNone);
Assert(jagged.GetOrNone(2, 0).IsNone);
(ListListT to FunVec2T) 2-dimensional jagged collection lengths and values of which are determined by the underlying list.
C#
var list = new List<List<char>>() { new() { 'a', 'b', 'c' }, new() { 'd' } };
FunVec2<char> jagged = new(list);
Assert(jagged.Length1 == 2);
Assert(jagged.Length2(0) == 3);
Assert(jagged.Length2(1) == 1);
Assert(jagged[0, 2] == 'c');
Assert(jagged.GetOrNone(1, 0) == Some('d'));
Assert(jagged.GetOrNone(0, 3).IsNone);
Assert(jagged.GetOrNone(2, 0).IsNone);

Fields

Length1 Length of the vector.
C#
var underlyingList = new List<int> { 10, 11, 12 };
FunVec1<int> vec = new(underlyingList);
Assert(vec.Length1 == 3);

Func<int, bool> underlyingFun = i => i % 2 == 0;
vec = new(underlyingFun, length1: Some(4));
Assert(vec.Length1, 4);

Func<int, bool> underlyingFun = i => i % 2 == 0;
vec = new(underlyingFun); // omitted optional argument 'length1' defaults to None -> no limit
Assert(vec.Length1 == int.MaxValue);
Length2 Length of the jagged array in the first dimension; i.e., number of 1D collections.
C#
var underlyingList = new List<List<int>> { new() { 1 }, new() { 2, 3, 4 } };
FunVec2<int> jagged = new(underlyingList);
Assert(jagged.Length1 == 2);
Assert(jagged.Length2(0) == 1);
Assert(jagged.Length2(1) == 3);

Func<int, int, bool> underlyingFun = (i, j) => (i + j) % 2 == 0;
FunVec2<bool> upperTriangular = new(underlyingFun, length1: Some(3), getLength2: Some<Func<int, int>>(i => i + 1));
Assert(jagged.Length1 == 3);
Assert(jagged.Length2(0) == 1);
Assert(jagged.Length2(1) == 2);
Assert(jagged.Length2(2) == 3);

FunVec2<Agent> bool = new(underlyingFun, length1: Some(2)); // omitted optional argument 'length2' defaults to None -> no limit
Assert(jagged.Length2(0) == jagged.Length2(1) == int.MaxValue);
UnderlyingScalar The unified collection might be constructed with a constant scalar value; hence, returning the scalar for all indices. If this is the case, HasUnderlyingScalar is true; and the field UnderlyingScalar equals to Some of the underlying scalar value.

Otherwise, HasUnderlyingScalar is false and UnderlyingScalar.IsNone.

C#
// vec[i] = 10, for all i.
UniJaggedD1<int> vec = new(10);
Assert(vec[3] == 10 and vec[42] == 10);
Assert(vec.Get(12) == Some(10));

// underlying constant can be obtained by the optional UnderlyingScalar field.
Assert(vec.HasUnderlyingScalar);
Assert(vec.UnderlyingScalar.IsSome);
Assert(vec.UnderlyingScalar == Some(10));
Assert(vec.UnderlyingScalar.Unwrap() == 10);

See Also