3

Let's say I have a bidimensional array of floats

float [,] myfloats = new float[10, 10]
FillWithValues(myfloats);

How can I convert this bidimensional float array, to a bidimensional bool array, using a random evaluating method?

I was hoping something like this:

bool[,] mybools;
mybools = myfloats.Select(myfloat => Evaluate(myfloat));

but that does not work...

Henka Programmer
  • 727
  • 7
  • 25
Enrique Moreno Tent
  • 24,127
  • 34
  • 104
  • 189
  • I was hoping there was a mapping method, to make it more elegant. But if that is your answer, please post the code :) Im unsure how to loop through a bidimensional array.. – Enrique Moreno Tent Aug 02 '16 at 17:37
  • See @Jon Skeet's answer here which should help to understand why "more elegant" is lacking: http://stackoverflow.com/questions/275073/why-do-c-sharp-multidimensional-arrays-not-implement-ienumerablet – blins Aug 02 '16 at 17:56

2 Answers2

3

Unfortunatly, multi-dimensional arrays are not compatible with LINQ and a little hard to handle. I don't think there is a way around this two-loop-solution:

bool[,] mybools = new bool[myfloats.GetLength(0), myfloats.GetLength(1)];
for (int x = 0; x<myfloats.GetLength(0); x++)
    for(int y=0; y<myfloats.GetLength(1); y++)
        mybools[x,y] = Evaluate(myfloats[x,y]);

Array.GetLength(Int32) gives you the size of the array in a specific dimension.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
1

It's not particularly efficient, but with two extension methods you can do this:

var floats = new float[3, 3] {
   { 1f, 2f, 3f },
   { 4f, 5f, 6f },
   { 7f, 8f, 9f }
};

Func<float, bool> floatToBool = f => f > 5f;

var bools =
   floats
   .ToJaggedArray()
   .Select(array => array.Select(floatToBool).ToArray())
   .ToArray()
   .To2DArray();

Note that you have to manipulate it back into an "array of arrays" to get back to a 2D array.

And it would work even better if we converted to enumerable of enumerables instead of to jagged arrays. Then it could look like this:

var bools =
   floats
   .ToEnumerableOfEnumerables()
   .Select(array => array.Select(floatToBool))
   .To2DArray();

The two extension methods for the first part are something like this:

[Pure, NotNull]
public static T[][] ToJaggedArray<T>([NotNull] this T[,] p2DArray) {
   var height = p2DArray.GetLength(0);
   var width = p2DArray.GetLength(1);

   var result = new T[height][];

   for (var row = 0; row < height; row++) {
      result[row] = new T[width];
      for (var col = 0; col < width; col++)
         result[row][col] = p2DArray[row, col];
   }

   return result;
}

[Pure, NotNull]
public static T[,] To2DArray<T>([NotNull] this T[][] pJaggedArray) {
   if (!pJaggedArray.Any() || !pJaggedArray[0].Any())
      return new T[0, 0];

   var height = pJaggedArray.Length;
   var width = pJaggedArray[0].Length;

   var result = new T[height, width];
   for (var r = 0; r < height; r++) {
      var subArray = pJaggedArray[r];
      if (subArray == null || subArray.Length != width)
         throw new InvalidOperationException("Jagged array was not rectangular.");

      for (var c = 0; c < width; c++)
         result[r, c] = subArray[c];
   }

   return result;
}

And for the second part are something like this:

[Pure, NotNull]
public static IEnumerable<IEnumerable<T>> ToEnumerableOfEnumerables<T>(
   [NotNull] this T[,] p2DArray
) {
   var height = p2DArray.GetLength(0);

   for (var row = 0; row < height; row++)
      yield return p2DArray.GetPartialEnumerable(row);
}

[Pure, NotNull]
public static IEnumerable<T> GetPartialEnumerable<T>(
   [NotNull] this T[,] p2DArray,
   int pRow
) {
   var width = p2DArray.GetLength(1);

   for (var col = 0; col < width; col++)
      yield return p2DArray[pRow, col];
}

[Pure, NotNull]
public static T[,] To2DArray<T>(
   [NotNull] this IEnumerable<IEnumerable<T>> pJaggedArray
) {
   if (!pJaggedArray.Any() || !pJaggedArray.First().Any())
      return new T[0, 0];

   var height = pJaggedArray.Count();
   var width = pJaggedArray.First().Count();

   var result = new T[height, width];
   var r = 0;
   foreach (var subArray in pJaggedArray) {
      if (subArray == null || subArray.Count() != width)
         throw new InvalidOperationException("Jagged array was not rectangular.");

      var c = 0;
      foreach (var item in subArray)
         result[r, c++] = item;

      r += 1;
   }

   return result;
}
Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80
  • Yuck! :) You overthinked it a bit: `Enumerable.Range(0, n).Select(x => Enumerable.Range(0, m).Select(y => (stuff[x, y] = (x * y)) > 10).ToArray()).ToArray();` - You can both return new array and assign values to existing one that way (ToList()/ToArray() might be advised to actually execute enumerable). Of course return type will be [n][m], not [n,m], because LINQ should not be used in this case ;) – PTwr Aug 05 '16 at 14:06