Most elegant way to get the array element by position? - c#

I have an array:
private int[,] _blocks = new int[6, 4];
It represents a set of blocks which is 6 deep horizontally and 4 deep vertically. Graphically it looks like this:
alt text http://www.angryhacker.com/toys/array.png
I need a function that would take in a number, from 1 to 24 and return the array element that matches. So for number 14, I'd get back _blocks[1, 2];
I've created a simplistic function:
private int GetBlockByPosition(int position)
{
int count = 0;
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 4; j++)
{
if (++count == position)
return _blocks[i, j];
}
}
return -1;
}
But this seems very wasteful and smells bad. Is there a more elegant and faster way?

Both in the horizontal direction and the vertical direction, you can see a pattern in your table of numbers. You can determine the horizontal position with position / 6 and a vertical position with position % 6 -- the modulo operation.
private int GetBlockByPosition(int position)
{
return _blocks[((position + 6) / 6) - 1, position % 6];
}
This makes mathematical sense. Division increases in chunks, and modulo (remainder on division) increases one by one. The math is pretty simple.

I'm not sure I follow, but why can't you just calculate he indexes based on the position? Something like this:
return _blocks[((position - 1) % 6),((position + 5) / 6) - 1];

I think you can do like this :
private int GetBlockByPosition(int position)
{
return _blocks[(position - 1 ) % 6 , (position - 1) / 6];
}

Are the numbers in your array ACTUALLY 1, 2, 3, ... or are you just using them as an example?
If there isn't any pattern to the data in your array that can be taken advantage of, then it looks like the simplistic option may be your best bet.
Or you could always make a one-time pass of the entire structure and build a hash table to be used in subsequent calls...

Depending on your definition of elegant, the following is perhaps a more functional way of solving the problem:
class Program
{
static void Main(string[] args)
{
var blocks = new int[,] {{1,2,3,4,5,6},{7,8,9,10,11,12},{13,14,15,16,17,18},{19,20,21,22,23,24}};
var position = blocks.FirstPositionOf(14);
Console.WriteLine(position.X + "," + position.Y + " has the element " + blocks[position.X,position.Y]);
}
}
class PositionTuple
{
public int X {get; set;}
public int Y {get; set;}
}
static class ArrayExtensions
{
public static IEnumerable<int> AsEnumerable(this int[,] someTwoDimensionalArray)
{
foreach (var num in someTwoDimensionalArray)
yield return num;
}
public static PositionTuple FirstPositionOf(this int[,] someTwoDimensionalArray, int someNumber)
{
return someTwoDimensionalArray
.AsEnumerable()
.Select((num, index) => new { Number = num, Tuple = new PositionTuple { X = index / (someTwoDimensionalArray.GetUpperBound(1) + 1), Y = index % (someTwoDimensionalArray.GetUpperBound(1)+1) }})
.Where(pair => pair.Number == someNumber)
.Select(pair => pair.Tuple)
.First();
}
}

I would make a more flexible function that can be used elsewhere if you need to
public static T Get2DArrayValueByPosition<T> (T[,] arr, int position)
{
// Gets the size of the array in first dimention
step = arr.GetUpperBound(0) + 1;
return arr[(position / step ), position % step];
}

Comprehensive solution considering the corner cases:
private int GetBlockByPosition(int position)
{
if(position % 6 == 0) { // last cells in each row. 6 gives [0,5]
return _blocks[(position / 6) - 1, (position - 1) % 6];
} else { // 11 gives [1,4]
return _blocks[position / 6 , (position % 6) - 1];
}
}

int result = GetByPosition(_blocks, 14);
private int GetByPosition(int[,] array, int position)
{
return GetByPositionBaseZero(array, position - 1);
}
private int GetByPositionBaseZero(int[,] array, int position)
{
int width = array.GetLength(0);
return array[position % width, position / width];
}

Related

Summing special object array of ints and objects

I have a List<object> which can contain either an integer value or another List<object>.
What I need to do, is to sum the values in the array, depending on its depth(If depth is 0, multiply by 0, if 1 then by 1 ... etc.)
Example array: [5, 2, [7, -1], 3, [6, [-13, 8], 4]]
How it should be calculated: 5 + 2 + 2 * (7 - 1) + 3 + 2 * (6 + 3 * (-13 + 8) + 4) = 12
What I managed to get:
public class Program
{
public static List<object> TestCase1()
{
List<object> test = new List<object>(){
5,
2,
new List<object>(){
7, -1
},
3,
new List<object>(){
6,
new List<object>(){
-13, 8
},
4,
},
};
return test;
}
public static int ProductSum(List<object> array)
{
int depthCounter = 1;
int totalSum = 0;
int tempSum = 0;
for (int i = 0; i < array.Count; i++)
{
if (array[i] is IList<object>)
{
totalSum += tempSum * depthCounter;
tempSum = 0;
depthCounter++;
}
else
{
tempSum += (int)array[i];
}
}
return totalSum;
}
static void Main(string[] args)
{
Console.WriteLine("Result = " + ProductSum(TestCase1()));
}
}
The result from my code is
The problem that I have, is I don't see a way, that I could iterate through an array to calculate it ... Maybe there is a way to sort an array of objects in some way to simplify it?
The method should call itself ("recursive"), when it encounters a nested list. It should also take a depth parameter, keeping track of the depth. Every time you call the function recursively, you pass depth + 1 as the new depth. Whenever you count something, you multiply by depth.
public static int ProductSum(List<object> list) => ProductSum(list, 1);
public static int ProductSum(List<object> list, int depth)
{
var sum = 0;
foreach (var thing in list) {
if (thing is List<object> innerList) {
sum += ProductSum(innerList, depth + 1) * depth;
} else if (thing is int x) {
sum += x * depth;
}
}
return sum;
}
You should do it recusively:
public static int ProductSum(List<object> array, int depthCounter)
{
int totalSum = 0;
for (int i = 0; i < array.Count; i++)
{
if (array[i] is List<object>)
{
totalSum += ProductSum(array[i] as List<Object>, depthCounter + 1);
}
else
{
totalSum += (int)array[i] * depthCounter;
}
}
return totalSum;
}
You call it this way:
ProductSum(TestCase1(), 0);
But I don't get the number you calculated, though: If all depth 0 candidates are multiplied by 0, these are... 0! ;)
Maybe there are some rules for your application that I don't know, and that's the reason why the calculations differ, but in the code you see how recursions work.

Check adjacent indices in a multidimensional array having into account the borders

I did this so I can know how many asterisks appear in the adjacent squares.
private int CheckAdjacents(Coordinate cord)
{
List<Coordinate> coordinates = new List<Coordinate>()
{
new Coordinate(cord.X - 1, cord.Y - 1),
new Coordinate(cord.X, cord.Y-1),
new Coordinate(cord.X + 1, cord.Y -1),
new Coordinate(cord.X + 1, cord.Y),
new Coordinate(cord.X + 1, cord.Y + 1),
new Coordinate(cord.X, cord.Y + 1),
new Coordinate(cord.X - 1, cord.Y + 1),
new Coordinate(cord.X - 1, cord.Y)
};
return coordinates.Count(x => _matrix.At(x).Value == '*');
}
The thing here is that obviously it returns an exception because is checking indexes that wouldn't be checked. What'd be the best way to skip those kind of indexes? Using a try/catch could be kinda tricky? Thanks!
EDIT:
Matrix class
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace MineSweeper
{
public record Coordinate (int X, int Y);
public record Size(int M, int N);
public class Matrix
{
private readonly Size _size;
private readonly Cell[,] _matrix;
private const char InitValue = '.';
public Matrix(Size size)
{
_size = size;
_matrix = new Cell[size.M, size.N];
Initialize();
}
private void Initialize()
{
for (int m = 0; m < _size.M; m++)
for (int n = 0; n < _size.N; n++)
_matrix[m, n] = new Cell(InitValue);
}
public Size GetSize()
=> _size;
public Cell At(Coordinate coordinate)
=> _matrix[coordinate.X, coordinate.Y];
public void SetMine(Coordinate coordinate)
=> _matrix[coordinate.X, coordinate.Y] = new Cell('*');
public void ChangeValue(Coordinate coordinate, char value)
=> _matrix[coordinate.X, coordinate.Y] = new Cell(value);
public Cell Open(Coordinate coordinate)
=> _matrix[coordinate.X, coordinate.Y];
public IEnumerable ToList()
=> _matrix.Cast<Cell>().ToList();
private string CellsAsString()
=> string.Concat(_matrix.OfType<Cell>().Select(c => c.Value));
public override bool Equals(object other)
=> this.CellsAsString().Equals((other as Matrix)?.CellsAsString());
public override int GetHashCode()
=> this.CellsAsString().GetHashCode();
}
}
EDIT(2):
PrintMatrix and Open methods from the main class.
public void Open(Coordinate coordinate)
{
if (_matrix.At(coordinate).Value == '*')
HasLose = true;
int numOfMines = _matrix.NeighborsOf(coordinate).Count(cell => cell.Value == '*');
_showedMatrix.ChangeValue(coordinate, char.Parse(numOfMines.ToString()));
HasWin = PlayerHasWin();
}
public String PrintMatrix()
{
string temp = "";
for (int x = 0; x < _size.M; x++)
{
for (int y = 0; y < _size.N; y++)
{
temp += _showedMatrix.At(new Coordinate(x, y)).Value;
}
temp += '\n';
}
return temp;
}
Notice that I'm using a showedMatrix which is another matrix with cells and its value for each one is a simple .. I'm using this new matrix so I can change its value and printing it.
These are the two tests that fail.
[Fact]
public void CellIsOpenWithoutAMineButWithOneMineAdjacent()
{
string printExpected = "1...\n....\n....\n....\n";
Matrix matrix = new Matrix(new(4, 4));
matrix.SetMine(new(0,1));
MineSweeper mineSweeper = new(matrix, 2);
mineSweeper.Open(new(0,0));
mineSweeper.PrintMatrix().Should().Be(printExpected);
}
[Fact]
public void CellIsOpenWithoutAMineButWithTwoMineAdjacent()
{
string printExpected = "2...\n....\n....\n....\n";
Matrix matrix = new Matrix(new(4, 4));
matrix.SetMine(new(0,1));
matrix.SetMine(new(1,0));
MineSweeper mineSweeper = new(matrix, 2);
mineSweeper.Open(new(0,0));
mineSweeper.PrintMatrix().Should().Be(printExpected);
}
Since I'm aware that my main class for these tests is putting 2 random mines plus the mines I'm putting by myself with the SetMine() method, I executed these tests several times to make sure that it was failing. The conclusion was that "2...\n....\n....\n....\n"; for some reason is always a 0 instead of a 2, or a 1.
I'd suggest an iterator method on the matrix itself, that took care of checking the bounds before returning the cells, something like this:
IEnumerable<Cell> NeighborsOf(Coordinate coord)
{
// if coord is not in bounds of the matrix, throw an argument exception
for (int x = Math.Max(coord.X - 1, 0); x <= Math.Min(coord.X + 1, _size.M - 1); x++)
{
for (int y = Math.Max(coord.Y - 1, 0); y <= Math.Min(coord.Y + 1, _size.N - 1); y++)
{
if ((x,y) == (coord.X, coord.Y)) continue;
yield return At(new Coordinate(x, y));
}
}
}
The for loops define the "3x3 window" of coordinates (central cell +/- 1) describing a maximum block of 9 cells, that has its edges limited by the Math.Min and Math.Max calls. Then, the central cell itself is skipped by the if check, resulting only on adjacent cells being returned.
Then, to count the asterisks, you just leverage this method:
_matrix.NeighborsOf(coordinate).Count(cell => cell.Value == '*');
Relying on exceptions to ignore the out-of-bounds coordinates would be considered a bad practice (as it would be an use of the "exception as control flow" anti-pattern) and also fairly poor performance-wise.
The neighbor idea also allows you to parameterize the "size" of the neighbor region, if that's useful to you.
You could add a method to the Matrix class, that returns true if both x and y are within their allowed ranges (0 <= x < M, 0 <= y < N) for a given Coordinate:
public bool IsValid(Coordinate coordinate) =>
0 <= coordinate.X && coordinate.X < _size.M &&
0 <= coordinate.Y && coordinate.Y < _size.N;
Then you can count only the valid cells:
return coordinates.Count(x => _matrix.IsValid(x) && _matrix.At(x).Value == '*');
Additionally, it makes sense to use this method for validation purpose in all other public methods of the Matrix class accepting Coordinate as an argument.

Interpolation Search, finding the closest value

i am trying to use an Interpolation Search algorithm to find a value and return it. (Which is what it does currently). I am trying to modify it so it returns a number which i can use to find the closest values to the inputted item if the item which was searched was not found within the array.
public static int InterSearch(double[] array, double data)
{
int size = array.Length;
int lo = 0;
int mid = -1;
int hi = array.Length - 1;
int index = -1;
int count = 0;
while (lo <= hi)
{
mid = (int)(lo + (((double)(hi - lo) / (array[hi] - array[lo])) * (data - array[lo])));
count++;
if (array[mid] == data)
{
index = mid;
break;
}
else
{
if (array[mid] < data)
lo = mid + 1;
else
hi = mid - 1;
}
}
return index;
}
You can use an aggregate that find the closest value.
this is a custom extension method but you get the idea.
public static double GetValueClosestTo(this List<double> values, double closestTo)
{
return values.Aggregate((x, y) => Math.Abs(x - closestTo) < Math.Abs(y - closestTo) ? x : y);
}
Let's say you have the following array {1, 5, 9.2, 6, 17} and you test the following number {6, 15, 5.2}. You will use the following code
var sourceArray = new [] {1, 5, 9.2, 6, 17}.ToList() // for simplicity i use a list
var closestToX = sourceArray.GetValueClosestTo(6); // this return 6
closestToX = sourceArray.GetValueClosestTo(15); // this return 17
closestToX = sourceArray.GetValueClosestTo(5.2); // this return 5

merge sort implementation query

I found this example of a merge sort algorithm online on a tutorial webpage and I have been trying to understand ow the code implements the algorithm. The example i found uses recursion and a temporary array to sort the array of unsorted algorithms.
My query is in the final step of the process. When copying the elements of the temporary array into the original array to sort the array. why does the algorithm decrements the right attribute instead of incrementing the left attribute? when i incremented the left left value the algorithm does not work.
class Assignment1
{
static void Main(string[] args)
{
Console.WriteLine("Size of array:");
int n = Convert.ToInt16(Console.ReadLine());
int[] unsorted = new int[n];
for(int i = 0; i < n; i++)
{
Console.WriteLine("Enter a number:");
unsorted[i] = Convert.ToInt16(Console.ReadLine());
}
Console.WriteLine("--------Sort---------");
Recursion_Sort(unsorted, 0, n - 1);
for (int i = 0; i < n; i++)
{
Console.WriteLine(unsorted[i]);
}
}
static public void Merge(int[] numbers, int left, int mid, int right, int n)
{
int[] tempArray = new int[n];
int i, lEnd, size, pos;
lEnd = mid - 1;
pos = left;
size = (right - left + 1);
while ((left <= lEnd) && (mid <= right))
{
if (numbers[left] <= numbers[mid])
{
tempArray[pos] = numbers[left];
pos++;
left++;
}
else
{
tempArray[pos] = numbers[mid];
pos++;
mid++;
}
}
while (left <= lEnd)
{
tempArray[pos] = numbers[left];
pos++;
left++;
}
while (mid <= right)
{
tempArray[pos] = numbers[mid];
pos++;
mid++;
}
Console.WriteLine(tempArray.Length);
for (i = 0; i < size; i++)
{
numbers[right] = tempArray[right];
right--;
}
}
static public void Recursion_Sort(int[] numbers, int left, int right)
{
int mid;
if (right > left)
{
mid = (right + left) / 2;
Recursion_Sort(numbers, left, mid);
Recursion_Sort(numbers, (mid + 1), right);
// we then merge the sorted sub arrays using the merge method
Merge(numbers, left, (mid + 1), right, numbers.Length);
}
}
}
left value is changing during merge and as you have code block
while (left <= lEnd)
{
//...
left++;
}
left will be finally assigned to lEnd + 1(the condition for ending while loop).
Otherwise right is not changing and is the last index of currently manipulated sequence.
Taking the risk of not answering the question like you want it, I would suggest LINQ. This is not merge sort in particular, but rather a concatenation of two arrays and then sorting.
If your array isn't so big that performance matters, you might want to go for this approach, because it's simple and less code (which is always good).
int[] arr1 = new[] { 1, 2, 3, 7, 8, 10 };
int[] arr2 = new[] { 4, 6, 9, 12, 15 };
int[] merged = arr1.Concat(arr2).OrderBy(n => n).ToArray();
Furthermore, I post this if it is interesting for others.

Is there a method to find the max of 3 numbers in C#?

The method should work like Math.Max(), but take 3 or more int parameters.
You could use Enumerable.Max:
new [] { 1, 2, 3 }.Max();
Well, you can just call it twice:
int max3 = Math.Max(x, Math.Max(y, z));
If you find yourself doing this a lot, you could always write your own helper method... I would be happy enough seeing this in my code base once, but not regularly.
(Note that this is likely to be more efficient than Andrew's LINQ-based answer - but obviously the more elements you have the more appealing the LINQ approach is.)
EDIT: A "best of both worlds" approach might be to have a custom set of methods either way:
public static class MoreMath
{
// This method only exists for consistency, so you can *always* call
// MoreMath.Max instead of alternating between MoreMath.Max and Math.Max
// depending on your argument count.
public static int Max(int x, int y)
{
return Math.Max(x, y);
}
public static int Max(int x, int y, int z)
{
// Or inline it as x < y ? (y < z ? z : y) : (x < z ? z : x);
// Time it before micro-optimizing though!
return Math.Max(x, Math.Max(y, z));
}
public static int Max(int w, int x, int y, int z)
{
return Math.Max(w, Math.Max(x, Math.Max(y, z)));
}
public static int Max(params int[] values)
{
return Enumerable.Max(values);
}
}
That way you can write MoreMath.Max(1, 2, 3) or MoreMath.Max(1, 2, 3, 4) without the overhead of array creation, but still write MoreMath.Max(1, 2, 3, 4, 5, 6) for nice readable and consistent code when you don't mind the overhead.
I personally find that more readable than the explicit array creation of the LINQ approach.
Linq has a Max function.
If you have an IEnumerable<int> you can call this directly, but if you require these in separate parameters you could create a function like this:
using System.Linq;
...
static int Max(params int[] numbers)
{
return numbers.Max();
}
Then you could call it like this: max(1, 6, 2), it allows for an arbitrary number of parameters.
As generic
public static T Min<T>(params T[] values) {
return values.Min();
}
public static T Max<T>(params T[] values) {
return values.Max();
}
off topic but here is the formula for middle value.. just in case someone is looking for it
Math.Min(Math.Min(Math.Max(x,y), Math.Max(y,z)), Math.Max(x,z));
Let's assume that You have a List<int> intList = new List<int>{1,2,3} if You want to get a max value You could do
int maxValue = intList.Max();
Maximum element value in priceValues[] is maxPriceValues :
double[] priceValues = new double[3];
priceValues [0] = 1;
priceValues [1] = 2;
priceValues [2] = 3;
double maxPriceValues = priceValues.Max();
If, for whatever reason (e.g. Space Engineers API), System.array has no definition for Max nor do you have access to Enumerable, a solution for Max of n values is:
public int Max(int[] values) {
if(values.Length < 1) {
return 0;
}
if(values.Length < 2) {
return values[0];
}
if(values.Length < 3) {
return Math.Max(values[0], values[1]);
}
int runningMax = values[0];
for(int i=1; i<values.Length - 1; i++) {
runningMax = Math.Max(runningMax, values[i]);
}
return runningMax;
}
You could try this code:
private float GetBrightestColor(float r, float g, float b) {
if (r > g && r > b) {
return r;
} else if (g > r && g > b) {
return g;
} else if (b > r && b > g) {
return b;
}
}
This function takes an array of integers. (I completely understand #Jon Skeet's complaint about sending arrays.)
It's probably a bit overkill.
public static int GetMax(int[] array) // must be a array of ints
{
int current_greatest_value = array[0]; // initializes it
for (int i = 1; i <= array.Length; i++)
{
// compare current number against next number
if (i+1 <= array.Length-1) // prevent "index outside bounds of array" error below with array[i+1]
{
// array[i+1] exists
if (array[i] < array[i+1] || array[i] <= current_greatest_value)
{
// current val is less than next, and less than the current greatest val, so go to next iteration
continue;
}
} else
{
// array[i+1] doesn't exist, we are at the last element
if (array[i] > current_greatest_value)
{
// current iteration val is greater than current_greatest_value
current_greatest_value = array[i];
}
break; // next for loop i index will be invalid
}
// if it gets here, current val is greater than next, so for now assign that value to greatest_value
current_greatest_value = array[i];
}
return current_greatest_value;
}
Then call the function :
int highest_val = GetMax (new[] { 1,6,2,72727275,2323});
// highest_val = 72727275
You can use if and else if method for three values but it would be much easier if you call call twice Math.Max method like this
Console.WriteLine("Largest of three: " + Math.Max(num1, Math.Max(num2, num3)));
Console.WriteLine("Lowest of three: " + Math.Min(num1, Math.Min(num2, num3)));
If you don't want to repeatedly calling the Max function, can do like this
new List<int>() { A, B, C, D, X, Y, Z }.Max()
in case you need sorting as well:
var side = new double[] {5,3,4}
Array.Sort(side);
//side[2] is a maximum
as an another variant:
T[] GetMax<T>(int number, List<T> source, T minVal)
{
T[] results = new T[number];
for (int i = 0; i < number; i++)
{
results[i] = minVal;
}
var curMin = minVal;
foreach (var e in source)
{
int resComp = Comparer.DefaultInvariant.Compare(curMin, e);
if (resComp < 0)
{
int minIndex = Array.IndexOf(results, curMin);
results[minIndex] = e;
curMin = results.Min();
}
}
return results;
}
var source = new int[] { 5, 5, 1, 2, 4, 3 }.ToList();
var result = GetMax(3, source, int.MinValue);

Categories

Resources