How find template from array? - c#

How find template in array ?
Template
int[] = {X, X, X}; //(example 3,3,3)
, or template
int[,] temp2 =
{
{X, X, ?}
{?, X, X}
}
Example
int[,] temp2 =
{
{3, 3, 1}
{2, 3, 3}
}
For example, in such an array?
int[,] a = new int[,]
{
{ 1, 4, 5, 3, 4 },
{ 1, 2, 3, 1, 3 },
{ 1, 1, 2, 4, 4 },
{ 4, 4, 3, 3, 3 },
{ 3, 4, 4, 5, 5 }
};
Is there a faster way than searching each cell and its neighboring cells?

If you are looking for patterns inside a bigger array, probably checking cell by cell is the only way to do it. You could do some complex optimizations for skipping the ? values and speedup a little, but I don't think it would easily work.
A sample code that should do what you asked:
// null means anything is ok, X is 0, Y is 1, Z is 2...
int?[,] temp = new int?[,]
{
{0, 0, null},
{null, 0, 0}
};
int[,] a = new int[,]
{
{ 0, 1, 1, 2, 4, 4, 1 },
{ 0, 1, 4, 4, 3, 3, 3 },
{ 0, 2, 3, 4, 4, 5, 5 }
};
int row, col;
bool success = CheckPattern(temp, a, out row, out col);
Console.WriteLine("Success: {0}, row: {1}, col: {2}", success, row, col);
and then
private static bool CheckPattern(int?[,] temp, int[,] data, out int row, out int col)
{
int rowsT = temp.GetLength(0);
int colsT = temp.GetLength(1);
int rowsD = data.GetLength(0);
int colsD = data.GetLength(1);
// Find the "maximum" value of the template (how many different
// condition are there... If there is only "X" then 1, "X", "Y" then 2,
// "X", "Y", "Z" then 3...
int max = -1;
for (int i = 0; i < rowsT; i++)
{
for (int j = 0; j < rowsT; j++)
{
if (temp[i, j] != null)
{
max = Math.Max(temp[i, j].Value, max);
}
}
}
// We save in an array the "current" values of "X", "Y", "Z", ...
int?[] values = new int?[max + 1];
for (int i = 0; i < rowsD - rowsT + 1; i++)
{
for (int j = 0; j < colsD - colsT + 1; j++)
{
Array.Clear(values, 0, values.Length);
bool success = true;
// Check the template
for (int k = 0; k < rowsT; k++)
{
for (int r = 0; r < colsT; r++)
{
if (temp[k, r] != null)
{
int? curr = values[temp[k, r].Value];
if (curr == null)
{
// If this is the first time we check this
// condition, then any value is good
values[temp[k, r].Value] = data[i + k, j + r];
}
else if (curr.Value == data[i + k, j + r])
{
// For subsequent instances we check this
// condition, then the data must have the
// value found in the previous instance
}
else
{
success = false;
break;
}
}
}
if (!success)
{
break;
}
}
if (success)
{
row = i;
col = j;
return true;
}
}
}
row = 0;
col = 0;
return false;
}
This piece of code should work even for multiple conditions "X", "Y"...

Related

Understanding Marching Square algorithm

The following picture is retrieved from Wikipedia:
I haven't understood this part:
I have two questions here:
Where did they obtain [8,4,1,2] from and what did they want to tell us by that?
Take a look at cell [0, 0] whose value is 13. If I go clockwise along with its contouring values, I obtain the binary string 0010 which is 2. How does the 1st cell-value become 13?
.
enum What
{
lines, surface, both
}
class Program
{
public static void Print(int[,] data, int xn, int yn)
{
for (int j = 0; j < yn; j++)
{
for (int i = 0; i < xn; i++)
{
Console.Write(data[i,j] + ", ");
}
Console.WriteLine();
}
}
public static int[,] normalize(int[,] data, int xn, int yn)
{
for (int j = 0; j < yn; j++)
{
for (int i = 0; i < xn; i++)
{
if (data[i, j] > 1)
{
data[i, j] = 0;
}
else
{
data[i, j] = 1;
}
}
}
return data;
}
public static int[,] marching_square(int x, int y, int[,] data, int isovalue, What what)
{
int xn = x;
int yn = y;
data = normalize(data, xn, yn);
int[,] bitMask = new int[xn - 1, yn - 1];
for (int j = 0; j < yn - 1; j++)
{
for (int i = 0; i < xn - 1; i++)
{
StringBuilder sb = new StringBuilder();
sb.Append(data[i, j]);
sb.Append(data[i, j + 1]);
sb.Append(data[i + 1, j]);
sb.Append(data[i + 1, j + 1]);
bitMask[i, j] = Convert.ToInt32(sb.ToString(), 2);
}
}
return bitMask;
}
static void Main(string[] args)
{
int[,] data = new int[,] {
{ 1,1,1,1,1 },
{ 1,2,3,2,1 },
{ 1,3,3,3,1 },
{ 1,2,3,2,1 },
{ 1,1,1,1,1 }
};
Print(data, 5,5);
int[,] bitMask = marching_square(5,5,data, 0, What.lines);
Print(bitMask, 4, 4);
}
}
Output:
1, 1, 1, 1, 1,
1, 2, 3, 2, 1,
1, 3, 3, 3, 1,
1, 2, 3, 2, 1,
1, 1, 1, 1, 1,
14, 10, 10, 11,
12, 0, 0, 3,
12, 0, 0, 3,
13, 5, 5, 7,
I inverted the bits. But, the output looks different.

How can i replace index values with other ones

Let's say i have an array of 6 elements of int type.
It looks like this
var array = new int [] { 0, 1, 2, 3, 4, 5 };
How can I randomly shuffle my array ensuring every index have a new value.
// Bad
// The number at index 3 did not change and still has a value of 3
new int [] { 1, 0, 5, 3, 2, 4 }
// Good:
// All the index have a new value
new int [] { 4, 2, 0, 5, 3, 1 }
I've tried to Shuffle, but sometimes some values will have the same index position
You could iterate over the array and always swap with a randomly choosen index which is bigger than the current one. That way the numbers get shuffled, but no element can be shuffled back.
Edit: This acutally works, try it:
using System;
class Program {
private static Random rnd = new Random();
public static void Main() {
for (var i = 0; i < 10000; i++) {
int[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Shuffle(array);
Console.WriteLine(String.Join(", ", array));
}
}
public static void Shuffle(int[] array) {
for (var i = 0; i + 1 < array.Length; i++) {
// generate j so that i < j < length
int j = rnd.Next(i + 1, array.Length);
// swap elements at i and j
var tmp = array[j];
array[j] = array[i];
array[i] = tmp;
// check
if (array[i] == i) {
throw new Exception(":(");
}
}
}
}
Also its very similar to Sattolo's algorithm, which would also work.

Check if array contains exact same sequence as other array

I have a question, I need to check if some array is part of greater array, it would be rather easy but I need to check if the greater array contains exact same sequence. For example
int[] greaterArray = {8, 3, 4, 5, 9, 12, 6 ... n - elements}
int[] lesserArray = {3, 4, 5}
Now I need to know if lesser array is part of this array but with same sequence so It it contains 3, 4, 5 next to each other in greater array.
I tried:
var exists = greaterArray.Intersect(lesserArray).Any();
But it return me information if any element of lesser array exists in greater array, not exact sequence. Any ideas?
int[] greaterArray = {8, 3, 4, 5, 9, 12, 6};
int[] lesserArray = { 3, 4, 5 };
bool sequenceFound = false;
for (int i = 0; i <= greaterArray.Length - lesserArray.Length; i++)
{
if (greaterArray.Skip(i).Take(lesserArray.Length).SequenceEqual(lesserArray))
{
sequenceFound = true;
break;
}
}
if (sequenceFound)
{
//sequence found
}
else
{
//sequence not found
}
Use the above code. It takes multiple sub-sequences from greaterArray of length equal to the length of lesserArray and matches it with lesserArray.
A bit more generic and without the use of LINQ:
int[] greaterArray = {8, 2, 4, 5, 9, 12, 3, 4, 5};
int[] lesserArray = {3, 4, 5};
for (int i = 0; i <= greaterArray.Length - lesserArray.Length; i++)
{
var sub = greaterArray.SubArray(i, lesserArray.Length);
if (Enumerable.SequenceEqual(sub, lesserArray))
{
Console.WriteLine("Equals!");
}
}
And this utils to get the SubArray:
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
This should do your work
int[] grtarr = { 8, 3, 4, 5, 9, 12, 6 };
int[] lsarr = { 3, 4, 5 };
List<int> lstGrtArr = grtarr.ToList();
List<int> lstLsrArr = lsarr.ToList();
bool sequenceMatch = false;
for (int i = 0; i < grtarr.Count(); i++)
{
if (lstGrtArr.Where(x => lstGrtArr.IndexOf(x) >= i).Take(lstLsrArr.Count()).SequenceEqual(lstLsrArr))
{
sequenceMatch = true;
break;
}
}
if(sequenceMatch)
{
//Do Something
}
static bool isPrefix(int[] source, int start_pos, int[] prefix)
{
bool result = start_pos + prefix.Length <= source.Length;
for (int i = 0; result && i < prefix.Length; ++i, ++start_pos)
result = source[start_pos] == prefix[i];
return result;
}
static bool Contains(int[] source, int[] prefix)
{
bool result = false;
for (int i = 0; !result && i < source.Length; ++i)
result = source[i] == prefix[0] ? isPrefix(source, i, prefix) : false;
return result;
}
Use this piece of code:
public bool ArraysEqual<T>(T[] a1, T[] a2)
{
if (ReferenceEquals(a1,a2))
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a1.Length; i++)
{
if (!comparer.Equals(a1[i], a2[i])) return false;
}
return true;
}
Or if you want to use Linq and don't care too much about performance, the easiest thing is:
var arrays_are_the_same = Enumerable.SequenceEqual(a1, a2);

How to check duplicate values horizontally and vertically in a 2D array?

Let's say I have an array like this :
9 1 2 0
1 5 2 5
7 1 6 3
4 3 2 7
I want to be able to create a loop that goes through the array vertically and horizontally to see if there's any duplicates.
For example, it will first check 9 1 7 4 to see if there's a dups. Then 1 5 1 3 and so on.
After that, it'll do 9 1 2 0 (which will tell me there's a dup), then 1 5 2 5 7, etc etc.
How can I do that?
While possible, a nested loops solution may not be the more straightforward way of solving it. In this case, using LINQ is must easier :
var matrix = new int[4, 4]
{
{ 9, 1, 2, 0 },
{ 1, 5, 2, 5 },
{ 7, 1, 6, 3 },
{ 4, 3, 2, 7 }
};
for (int i = 0; i < 4; i++)
{
var row = Enumerable.Range(0, 4).Select(x => matrix[i, x]);
if (row.Distinct().Count() != 4)
Console.WriteLine("Duplicated value in row {0} : {1}",
i + 1, string.Join(", ", row));
}
for (int i = 0; i < 4; i++)
{
var column = Enumerable.Range(0, 4).Select(x => matrix[x, i]);
if (column.Distinct().Count() != 4)
Console.WriteLine("Duplicated value in column {0} : {1}",
i + 1, string.Join(", ", column));
}
Output :
Duplicated value in row 2 : 1, 5, 2, 5
Duplicated value in column 2 : 1, 5, 1, 3
Duplicated value in column 3 : 2, 2, 6, 2
I have gotten a working solution using nested For Loops. This will write "Nothing" to the console when the index used to check(horizontal or vertical) is zero to avoid an ArrayIndexOutOfBoundsException. It writes "Duplicate No." and then the number that was duplicate to the console. I have posted my full working example below along with the output from console:
For horizontal:
int[,] array = new int[5, 4] { { 1, 2, 3, 4 }, { 5, 5, 5, 5 }, { 9, 5, 11, 12 }, { 13, 14, 15, 16 }, { 17, 18, 19, 20 } } ;
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
if (j == 0)
{
Console.WriteLine("Nothing");
}
else if (array[i, j] == array[i, j - 1])
{
Console.WriteLine("Duplicate No." + array[i, j].ToString());
}
}
}
For vertical:
for (int i = 0; i < array.GetLength(1); i++)
{
for (int j = 0; j < array.GetLength(0); j++)
{
if (j == 0)
{
Console.WriteLine("Nothing");
}
else if (array[j, i] == array[j - 1, i])
{
Console.WriteLine("Duplicate No." + array[i, j].ToString());
}
}
}
Output from both horizontal and vertical:
Nothing
Nothing
Duplicate No. 5
Duplicate No. 5
Duplicate No. 5
Nothing
Nothing
Nothing
Nothing
Nothing
Duplicate No. 5
Nothing
Nothing
I create a class that allow you to enumerate through the array
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication88
{
class Program
{
static void Main(string[] args)
{
EnumerateArray eArray = new EnumerateArray() {
new List<int>() {1,2,3,4},
new List<int>() {5,6,7,8},
new List<int>() {9,10,11,12},
new List<int>() {13,14,15,16},
new List<int>() {17,18,19,20}
};
foreach (List<int> x in eArray)
{
Console.WriteLine(string.Join(",", x.Select(y => y.ToString()).ToArray()));
}
Console.ReadLine();
}
}
public class EnumerateArray : IEnumerator, IEnumerable
{
public List<List<int>> myArray { get; set;}
int row = 0;
int col = 0;
int numCols = 0;
int numRows = 0;
public int Count { get; set; }
public int[] current = null;
Boolean finishedCol = false;
public EnumerateArray()
{
myArray = new List<List<int>>();
}
public EnumerateArray(List<List<int>> array)
{
myArray = array;
Reset();
numRows = array.Count;
numCols = array[0].Count;
Count = numCols + numRows;
}
public void Add(List<int> array)
{
myArray.Add(array);
numRows = myArray.Count;
numCols = array.Count;
Count = numCols + numRows;
}
public void Add(List<List<int>> array)
{
myArray = array;
Reset();
numRows = array.Count;
numCols = array[0].Count;
Count = numCols + numRows;
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public EnumerateArray GetEnumerator()
{
return new EnumerateArray(myArray);
}
public bool MoveNext()
{
Boolean done = true;
if (finishedCol == false)
{
if (col < numCols - 1)
{
col++;
}
else
{
finishedCol = true;
row = 0;
}
}
else
{
if (row < numRows - 1)
{
row++;
}
else
{
done = false;
}
}
return done;
}
public void Reset()
{
row = -1;
col = -1;
finishedCol = false;
Count = numCols + numRows;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public List<int> Current
{
get
{
try
{
List<int> _array = new List<int>();
if (finishedCol == false)
{
for (int _row = 0; _row < numRows; _row++)
{
_array.Add(myArray[_row][ col]);
}
}
else
{
_array.AddRange(myArray[row]);
}
return _array;
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
}

Printing 2D array in matrix format

I have a 2D array as follows:
long[,] arr = new long[4, 4] {{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 }};
I want to print the values of this array in matrix format like:
0 0 0 0
1 1 1 1
0 0 0 0
1 1 1 1
How can I do this?
You can do it like this (with a slightly modified array to show it works for non-square arrays):
long[,] arr = new long[5, 4] { { 1, 2, 3, 4 }, { 1, 1, 1, 1 }, { 2, 2, 2, 2 }, { 3, 3, 3, 3 }, { 4, 4, 4, 4 } };
int rowLength = arr.GetLength(0);
int colLength = arr.GetLength(1);
for (int i = 0; i < rowLength; i++)
{
for (int j = 0; j < colLength; j++)
{
Console.Write(string.Format("{0} ", arr[i, j]));
}
Console.Write(Environment.NewLine + Environment.NewLine);
}
Console.ReadLine();
like so:
long[,] arr = new long[4, 4] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 1, 1, 1, 1 } };
var rowCount = arr.GetLength(0);
var colCount = arr.GetLength(1);
for (int row = 0; row < rowCount; row++)
{
for (int col = 0; col < colCount; col++)
Console.Write(String.Format("{0}\t", arr[row,col]));
Console.WriteLine();
}
I wrote extension method
public static string ToMatrixString<T>(this T[,] matrix, string delimiter = "\t")
{
var s = new StringBuilder();
for (var i = 0; i < matrix.GetLength(0); i++)
{
for (var j = 0; j < matrix.GetLength(1); j++)
{
s.Append(matrix[i, j]).Append(delimiter);
}
s.AppendLine();
}
return s.ToString();
}
To use just call the method
results.ToMatrixString();
Here is how to do it in Unity:
(Modified answer from #markmuetz so be sure to upvote his answer)
int[,] rawNodes = new int[,]
{
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 }
};
private void Start()
{
int rowLength = rawNodes.GetLength(0);
int colLength = rawNodes.GetLength(1);
string arrayString = "";
for (int i = 0; i < rowLength; i++)
{
for (int j = 0; j < colLength; j++)
{
arrayString += string.Format("{0} ", rawNodes[i, j]);
}
arrayString += System.Environment.NewLine + System.Environment.NewLine;
}
Debug.Log(arrayString);
}
Your can do it like this in short hands.
int[,] values=new int[2,3]{{2,4,5},{4,5,2}};
for (int i = 0; i < values.GetLength(0); i++)
{
for (int k = 0; k < values.GetLength(1); k++) {
Console.Write(values[i,k]);
}
Console.WriteLine();
}
you can do like this also
long[,] arr = new long[4, 4] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 1, 1, 1, 1 }};
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Console.Write(arr[i,j]+" ");
}
Console.WriteLine();
}
If using a square matrix:
int[,] mat = new int[,]{{ 1, 0, 0 },{ 0, 1, 0},{ 0, 0, 1}};
int i=1;
foreach(int e in mat){
Console.Write(i%Math.Sqrt(mat.Length)==0? $"{e}\n" : e);
i+=1;
}

Categories

Resources