Related
I'm trying to find indices for all contiguous elements that occurrence more than Threshold in one dimensional integer array using c#
double[] x = new double[20]{1,1,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,1,1};
I want to get indices for this x[] vector as the following for 0 values
threshold=4
start-index[0] =2
end-index[0] =5
start-index[1] =8
end-index[1] =11
i try to use this code, but there is many problems in it
public void myFunc(double[] x, ref List<int> start, ref List<int> end,int matchingVal,int threshold)
{
int count = 0;
for (int i = 0; i < x.Length; i++)
{
for (int j = i+1; j < threshold; j++)
{
if (x[i] == x[j] && x[i] == matchingVal)
{
count++;
}
else
{
break;//no contiguous element
}
if (count >= threshold)
{
start.Add(i);
end.Add(i + count);
count = 0;
}
else
continue;
}
}
}
If you are willing to use MoreLINQ, consider using GroupAdjacent.
An example is below. Basically, it takes the original array, uses Select to include the index, uses GroupAdjacent to group adjacent values together, uses Where and Count to check there are at least 4 adjacent values, then uses Select to project an anonymous type including the value and its first and last index (this can be changed to project to whatever concrete type you want). Then string.Join is used to write it to the console so you can see the results.
using System;
using System.Linq;
using MoreLinq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
double[] x = new double[20] { 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1 };
var results = x.Select((value, index) => new { value, index })
.GroupAdjacent(z => z.value)
.Where(z => z.Count() >= 4)
.Where(z => z.Key == 0) // it is unclear whether you want to filter for specific values - if so, this is how to do it
.Select(z =>
new { value = z.Key, firstIndex = z.First().index, lastIndex = z.Last().index })
.ToList();
Console.WriteLine(string.Join(Environment.NewLine, results.Select(z => $"{z.value} - {z.firstIndex} - {z.lastIndex}")));
Console.ReadLine();
}
}
}
Updated added more tests and fixed an issue thanks to #AntonínLejsek
Given
public static IEnumerable<(int start, int finish)> GetStuff(int thresh, double[] ary)
{
int start = 0, count = 1;
for (var i = 0; i < ary.Length - 1; i++, count++)
if (ary[i] == ary[i + 1])
{
if (count == 1) start = i;
}
else
{
if (count >= thresh) yield return (start, i);
count = 0;
}
if (count >= thresh) yield return (start, ary.Length-1);
}
Usage
foreach (var tuple in GetStuff(3,ary))
Console.WriteLine($"start : {tuple.start}, finish : {tuple.finish}");
Output
var ary = new double[] { 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1 };
start : 2, finish : 5
start : 8, finish : 11
start : 12, finish : 14
start : 15, finish : 17
var ary = new double[] { 1, 1, 1 ,0 };
start : 0, finish : 2
var ary = new double[] { 1, 1, 1 };
start : 0, finish : 2
C#,
Console Application,
Virtual Studio 2015,
Paralelles: Windows 8.1.
The code is as follows:
class txt_program
{
public void txt()
{
/* 0 */
int[] M_array_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* 1 */
int[] M_array_1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* 2 */
int[] M_array_2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// etc.
// the M matrix
int[][] M = { M_array_0, M_array_1, M_array_2, M_array_3, M_array_4,
M_array_5, M_array_6, M_array_7, M_array_8, M_array_9, M_array_10,
M_array_12, M_array_13 };
// the time pick is beeing called into this item.
Time_pick_2 T2 = new Time_pick_2();
// the if loop making
// 0
if (T2.M_build_0() == true)
{
int nr_0 = 0;
for (int i = nr_0; i < nr_0 + 2; i++)
{
M[1][i] = M_array_0[i] + 1;
}
}
// 1
else if (T2.M_build_1() == true)
{
int nr_1 = 1;
for (int i = nr_1; i < nr_1 + 2; i++)
{
M[1][i] = M_array_1[i] + 1;
}
}
// 2
else if (T2.M_build_2() == true)
{
int nr_2 = 2;
for (int i = nr_2; i < nr_2 + 2; i++)
{
M[2][i] = M_array_2[i] + 1;
}
}
// etc.
using (StreamWriter SW = new StreamWriter(#"txt.txt"))
{
// the loops creating the .txt-file.
for (int i = 0; i < M.GetLength(0); i++)
{
for (int a = 0; a < 13; a++)
{
SW.Write(" " + M[i][a]);
}
SW.WriteLine(M);
}
}
}
}
}
As pastebin:
http://pastebin.com/3HDYwzzZ
The output is given as:
0 0 0 0 0 0 0 0 0 0 0 0 0System.Int32[][]
0 1 1 0 0 0 0 0 0 0 0 0 0System.Int32[][]
0 0 0 0 0 0 0 0 0 0 0 0 0System.Int32[][]
// etc.
I checked some other post about the appearance off System.Int32[][] but in all of the cases it was code that didnot generate any output except System.Int32[], which meant that the code could not interpret the for-loopcreating the output. Here the correct output is displayed but still with the System.Int32[][] end. Why is this and what am I doing wrong?
By default, the ToString method returns the type of the object. So, if you print a non-primitive type without overriding the ToString method (defined in Object class), you will get the type name instead.
The problem line in your case is:
SW.WriteLine(M);
You are outputting the whole array after your inner loop. If you want a newline you could use Console.WriteLine("")
using (StreamWriter SW = new StreamWriter(#"txt.txt"))
{
// the loops creating the .txt-file.
for (int i = 0; i < M.GetLength(0); i++)
{
for (int a = 0; a < 13; a++)
{
SW.Write(" " + M[i][a]);
}
//SW.WriteLine(M); // <-- this line was generating your output
SW.WriteLine("");
}
}
As Heinzbeinz already said you are printing an array which in C# wil result in printing the object type for example:
int[] ar1 = {0,1,2,3};
int[] ar2 = {0,1,2,3};
int[][] m = {ar1,ar2};
Console.WriteLine(m);
wil result in printing System.Int32[][]
I have a list of numbers 1 and 0 only with fixed size of 25.
Example:
List<int>() { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
And I need to reorder or sort the list to:
Pattern A:
List<int>() { 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 };
or
Pattern B:
List<int>() { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0 };
Max no of "1" in the list will always less than 13. The list will loop and search for nearest "1" and replace with current index if current index is "0" (either start from left or right only).
Here are my code snippets to produce both patterns above:
List SlotMapLP1 = new List() { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int i = 0, j = 0, k = 0, waferCount = 0, loopCtr = 0;
for (i = 0; i < SlotMapLP1.Count; i++ )
{
if (SlotMapLP1[i] == 1)
waferCount++;
}
List<int> ptnOne = new List<int>(SlotMapLP1);
List<int> ptnTwo = new List<int>(SlotMapLP1);
j = ptnOne.Count - 1;
while (j >= 0 && loopCtr <= waferCount) //list will start to traverse from right to left
{
if ((ptnOne[j] == 0 && (j + 1) % 2 > 0))
{
k = j - 1;
while (k >= 0)
{
if (ptnOne[k] == 1 && (ptnOne[k] != ptnOne[j]))
{
ExtensionMethods.Swap(ptnOne, k, j); //swap the two items
loopCtr++;
break;
}
k--;
}
}
else
{
if (j == 0 || j + 1 == ptnOne.Count) break;
if (ptnOne[j - 1] == 0 && ptnOne[j + 1] == 1)
{
k = j - 1;
while (k >= 0)
{
if (ptnOne[k] == 0 && (ptnOne[k] != ptnOne[j]))
{
ExtensionMethods.Swap(ptnOne, j, k); //swap the two items
loopCtr++;
break;
}
k--;
}
}
else
{
k = j - 1;
while (k >= 0)
{
if (ptnOne[k] == 1 && (ptnOne[k] != ptnOne[j]))
{
ExtensionMethods.Swap(ptnOne, j, k); //swap the two items
loopCtr++;
break;
}
k--;
}
}
}
j--;
}
loopCtr = 0; j = 0; k = 0;
while (j < ptnTwo.Count && loopCtr <= waferCount)//list will start to traverse from left to right
{
if (ptnTwo[j] == 0 && (j + 1) % 2 > 0)
{
k = j + 1;
while (k < ptnTwo.Count)
{
if (ptnTwo[k] == 1 && (ptnTwo[k] != ptnTwo[j]))
{
ExtensionMethods.Swap(ptnTwo, j, k); //swap the two items
loopCtr++;
break;
}
k++;
}
}
else
{
if (j == 0 || j + 1 == ptnOne.Count) break;
if (ptnTwo[j + 1] == 0 && ptnTwo[j - 1] == 1)
{
k = j + 1;
while (k < ptnTwo.Count)
{
if (ptnTwo[k] == 0 && (ptnTwo[k] != ptnTwo[j]))
{
ExtensionMethods.Swap(ptnTwo, j, k); //swap the two items
loopCtr++;
break;
}
k++;
}
}
else
{
k = j + 1;
while (k < ptnTwo.Count)
{
if (ptnTwo[k] == 1 && (ptnTwo[k] != ptnTwo[j]))
{
ExtensionMethods.Swap(ptnTwo, j, k); //swap the two items
loopCtr++;
break;
}
k++;
}
}
}
j++;
}
However, I do face some problem. Not all list input can be sorted or reorder to alternately if I use this method.
Are there better way or method to perform this type of sorting?
There's a solution that doesn't involve swapping elements in the list. You only have to figure out the pattern.
If there is only one 1:
1000000000000000000000000
There's a "1" followed by 24 zeros.
If there are 2 ones:
1010000000000000000000000
There's a "101" pattern followed by 22 zeros.
See where I'm getting at?
For 3 ones:
1010100000000000000000000
There's a "10101" pattern followed by 20 zeros.
So you only have to count the number of ones and build your pattern from there. The algorithm then becomes:
Let n = number of ones in the list
If there are no ones, both patterns A and B is just 25 zeros.
Else build alternating pattern of length n * 2 - 1.
For pattern A, concatenate 25 - (n * 2 - 1) zeros and the alternating pattern.
For pattern B, concatenate the alternating pattern and 25 - (n * 2 - 1) zeros. (Or the reverse of pattern A)
if the size is actually fixed to 25 items I think that it is easier to count the amount of 1 and build a new list according to that amount.
I have test with Pattern A and Pattern B but it will make my codes become longer due to multiple checking required. I created new pattern which I test so far is the best for my application which require movement of hardware. Just to share my idea.
Pattern C :
List() { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
Here are the code portion:
List<int> SlotMapLP1 = new List<int>();
for (int x = 0; x < 25; x++)
{
SlotMapLP1.Add(int.Parse(waferArrangement.Substring(x, 1))); //input string contains 1 and 0; where 1 should be max 12 count only
}
int i = 0, j = 0, k = 0, waferCount = 0;
for (i = 0; i < SlotMapLP1.Count; i++ )
if (SlotMapLP1[i] == 1)
waferCount++;
List<int> ptnOne = new List<int>(SlotMapLP1);
for (j = 0; j < ptnOne.Count; j++ )
{
if(j == 0 || j % 2 == 0)
{
if (ptnOne[j] == 1)
{
k = j + 1;
while (k < ptnOne.Count())
{
if (ptnOne[k] == 0)
{
ExtensionMethods.Swap(ptnOne, k, j); //swap position
break;
}
k++;
}
}
}
else
{
if (ptnOne[j] == 0)
{
k = j + 1;
while (k < ptnOne.Count())
{
if (ptnOne[k] == 1)
{
ExtensionMethods.Swap(ptnOne, k, j); //swap position
break;
}
k++;
}
}
}
}
I tested with several inputs and the sorting/reorder function works well.
i am searching for an algorithm that can find the the biggest Areas in a Grid.
if i have something like this:
Red Blocks = Blocks with Collision
i have to check 28 collision Objekts.
I need an algorithm that can find this:
now i only have to check 5 Objekts.
Is there an easy c# algorithm for that?
If you wanted the absolute minimum number of rectangles, then I would suggest this answer to you. Since you want easy, though, here's my suggestion, which is 2-competitive with the minimum. First, by scanning the rows one by one, find the minimum exact cover with rectangles only one row high.
00000000
1 2
3 44 5
6 77 8
99999999
Now for each pair of adjacent rows in turn, try to merge their rectangles. Assuming that they are sorted by horizontal position, then the loop looks like a sorted merge.
00000000
--------
1 2
No merges possible.
1 2
--------
3 44 5
Merge 1, 3 and 2, 5.
1 2
1 44 2
--------
6 77 8
Merge 1, 6 and 4, 7 and 2, 8.
1 2
1 44 2
1 44 2
--------
99999999
No merges possible. The final result is the following.
00000000
1 2
1 44 2
1 44 2
99999999
here is a solution for Unity
using UnityEngine;
using System.Collections;
public class CollisionTileMerger:MonoBehaviour{
ArrayList rects = new ArrayList();
public int[,] rowCheck(int[,]array)
{
int y = array.GetLength(0);
int x = array.Length /y ;
int count = 1;
ArrayList rec = new ArrayList ();
for(int i=0; i< y ;i++){
for(int j=0; j< x ;j++)
{
if(array[i,j] == -1)
{
array[i,j] = count;
rec.Add(i);
rec.Add(j);
}
else
{
if(rec.Count>0)
{
rects.Add (rec);
rec = new ArrayList();
count++;
}
}
}
if(rec.Count>0)
{
rects.Add (rec);
rec = new ArrayList();
count++;
}
}
return array;
}
public int[,] Merger(int[,]array)
{
int y = array.GetLength(0);
int x = array.Length /y ;
int[,] coppy = (int[,])array.Clone ();
for (int i=0; i< y-1; i++)
{
int row = i;
for (int j=0; j< x; j++)
{
if(coppy[row,j]>0&&coppy[row+1,j]>0)
{
if(j==0)
{
coppy[row+1,j] = coppy[row,j];
}
else
{
if((coppy[row,j-1]>0&&coppy[row+1,j-1]>0)||(coppy[row,j-1]==0&&coppy[row+1,j-1]==0))
{
coppy[row+1,j] = coppy[row,j];
if(j==x-1)
{
//letzte Zeile
//speichern
array = (int[,])coppy.Clone ();
}
}
else
{
//zurücksetzen
coppy = (int[,])array.Clone ();
}
}
}
else if(coppy[row,j]==0&&coppy[row+1,j]==0)
{
//speichern
array = (int[,])coppy.Clone ();
}
else
{
//zurücksetzen
coppy = (int[,])array.Clone ();
}
}
}
//speichern
array = (int[,])coppy.Clone ();
return array;
}
// Use this for initialization
void Start () {
int[,] a = new int[,] {
{-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0, 0, 0, 0, 0, 0,-1},
{-1, 0, 0, -1, 0, 0, 0,-1},
{-1, 0, 0, -1, 0, 0, 0,-1},
{-1, 0, 0, -1, 0, 0, 0,-1},
{-1, 0, 0,-1,-1, 0, 0,-1},
{-1, 0, 0,-1,-1, 0, 0,-1},
{-1, 0, 0,-1,-1, 0, 0,-1},
{-1,-1,-1,-1,-1,-1,-1,-1}};
displayArray (Merger(rowCheck (a)));
}
// Update is called once per frame
void Update () {
}
public void displayArray(int[,]array)
{
int y = array.GetLength(0);
int x = array.Length /y ;
string row="";
for (int i = 0; i< y; i++)
{
for(int j = 0; j<x;j++)
{
row+= array[i,j]+" ";
}
row+= "\r\n";
}
Debug.Log(row);
/*foreach( int a in array )
{
Debug.Log( array.GetLength(0) );
Debug.Log( array.Length );
}*/
}
}
supposing I have a matrix like
0 -1 0 0
0 0 -1 0
0 0 0 0
0 0 -1 -1
so in this case The matrix represents:
0's are conected and -1 are not
How can I get Adjacency matrix from it?
I know
h[i][j] = 0, if there is no direct link from i to j
(i and j are not neighbors)
h[i][j] = 1, if there is a direct link from i to j
(i and j are neighbors)
so I am doing something like:
Int32[,] original = new int[4, 4]
{
{0, -1, 0, 0},
{0, 0, -1, 0},
{0, 0, 0, 0},
{0, 0, -1, -1}
}
Int32[,] adjacent;
for (int i = 0; i < original.GetLength(0); i++){
for (int j = 0; j < original.GetLength(1); j++) {
//How to know if there is direct link from i to j
//if(){
// adjacent[i,j]=0;
//}else{
// adjacent[i,j]=1;
//}
}
}
The original code has a problem - the matrixes adjacent and original are not usually the same size.
But it's close, in a way.
Code not tested:
int size = original.GetLength(0) * original.GetLength(1);
int[,] adjacent = new int[size, size];
for (int i = 0; i < original.GetLength(0); i++) {
for (int j = 0; j < original.GetLength(1); j++) {
if (original[i, j] == 0) {
// up/down
if (j > 0 && original[i, j - 1] == 0) {
adjacent[remap(i, j), remap(i, j - 1)] = 1;
adjacent[remap(i, j - 1), remap(i, j)] = 1;
}
// left/right
if (i > 0 && original[i - 1, j] == 0) {
adjacent[remap(i, j), remap(i - 1, j)] = 1;
adjacent[remap(i - 1, j), remap(i, j)] = 1;
}
}
}
}
remap maps a 2D point to a "node index". It may need more arguments. It could be something like:
int remap(int i, int j, int width)
{
return width * i + j;
}
There are other possibilities, but this is the simplest.
The adjacency matrix is an n by n matrix for a graph with n nodes (see an example here), as #harold has stated already. So you need to map between the physical (i,j) coordinates of the node in your grid, and the node number which is between 0 and n-1.
Here is some code that is along the right lines. I have looked at the output in the debugger and checking the first couple of rows it looked ok.
class Program
{
static void AddToAdjacencyMatrix(Int32[,] adjacency, Int32[,] original,
Dictionary<Tuple<int, int>, int> coordinate2NodeNum,
Tuple<int, int> fromCoord, int deltaX, int deltaY)
{
Tuple<int, int> toCoord = new Tuple<int, int>(
fromCoord.Item1 + deltaX, fromCoord.Item2 + deltaY);
try { // quick and dirty way of catching out of range coordinates
if (original[toCoord.Item1,toCoord.Item2] == 0) {
int fromNodeNum = coordinate2NodeNum[fromCoord];
int toNodeNum = coordinate2NodeNum[toCoord];
adjacency[fromNodeNum, toNodeNum] = 1;
adjacency[toNodeNum, fromNodeNum] = 1;
}
}
catch {
}
}
static void Main(string[] args)
{
Int32[,] original = new int[4, 4]
{
{0, -1, 0, 0},
{0, 0, -1, 0},
{0, 0, 0, 0},
{0, 0, -1, -1}
};
// Adjacency matrix has column and row headings for each node in graph
// Therefore we need to map between the node number in the adjacency matrix
// (i.e. the column or row heading) and the physical grid coordinates
Dictionary<int, Tuple<int, int>> nodeNum2Coordinate = new Dictionary<int, Tuple<int, int>>();
Dictionary<Tuple<int, int>, int> coordinate2NodeNum = new Dictionary<Tuple<int, int>, int>();
int nodeCount = 0;
for (int i = 0; i < original.GetLength(0); i++){
for (int j = 0; j < original.GetLength(1); j++) {
if (original[i, j] == 0) {
Tuple<int, int> coord = new Tuple<int, int>(i,j);
nodeNum2Coordinate.Add(nodeCount, coord);
coordinate2NodeNum.Add(coord, nodeCount);
nodeCount++;
}
}
}
// Now create the adacency matrix
Int32[,] adjacency = new int[nodeCount, nodeCount];
for (int i = 0; i < original.GetLength(0); i++){
for (int j = 0; j < original.GetLength(1); j++) {
if (original[i, j] == 0) {
Tuple<int, int> fromCoord = new Tuple<int, int>(i,j);
// Check connections
AddToAdjacencyMatrix(adjacency, original, coordinate2NodeNum, fromCoord,
-1, 0); // UP
AddToAdjacencyMatrix(adjacency, original, coordinate2NodeNum, fromCoord,
+1, 0); // DOWN
AddToAdjacencyMatrix(adjacency, original, coordinate2NodeNum, fromCoord,
0, -1); // LEFT
AddToAdjacencyMatrix(adjacency, original, coordinate2NodeNum, fromCoord,
0, +1); // UP
}
}
}
Console.ReadLine();
}
}