I am playing around with sorting arrays and I figured out how to MergeSort an int array. But I cant figure out to MergeSort a string array. Sorting string array is easy enough when normal sorting but Merge Sort is different. The code I have done so far is below and is working on int arrays.
public int number = 1;
public void mergeSort(int[] sortArray, int lower, int upper)
{
int middle;
if (upper == lower)
return;
else
{
middle = (lower + upper) / 2;
mergeSort(sortArray, lower, middle);
mergeSort(sortArray, middle + 1, upper);
Merge(sortArray, lower, middle + 1, upper);
}
}
public void Merge(int[] sortArray, int lower, int middle, int upper)
{
string[] temp = new string[sortArray.Length];
int lowEnd = middle - 1;
int low = lower;
int n = upper - lower + 1;
while ((lower <= lowEnd) && (middle <= upper))
{
if (sortArray[lower] <= sortArray[middle])
{
temp[low] = sortArray[lower].ToString();
low++;
lower++;
}
else
{
temp[low] = sortArray[middle].ToString();
low++;
middle++;
}
}
while (lower <= lowEnd)
{
temp[low] = sortArray[lower].ToString();
low++;
lower++;
}
while (middle <= upper)
{
temp[low] = sortArray[middle].ToString();
low++;
middle++;
}
for (int i = 0; i < n; i++)
{
sortArray[upper] = Int32.Parse(temp[upper]);
upper--;
}
}
private void btnExecute_Click(object sender, EventArgs e)
{
String arraylength;
int num;
arraylength = Microsoft.VisualBasic.Interaction.InputBox("Enter a number to determine the length of the array", "Enter Number");
try
{
while (!(int.TryParse(arraylength, out num)))
{
MessageBox.Show("Not a valid number, try again.");
arraylength = Microsoft.VisualBasic.Interaction.InputBox("Enter a number a to determine the length of the array", "Enter Number");
}
}
catch (Exception ex)
{
MessageBox.Show("Value entered is not in a valid format");
}
int intlength = Int32.Parse(arraylength);
string[] stringsArray = new string[intlength];
int arraypos = 0;
// For display purposes
int positionvalue = 1;
txtOutput.Text += "Unsorted array: \r\n";
foreach (string s in stringsArray)
{
string arrayvalue = Microsoft.VisualBasic.Interaction.InputBox("Enter a number for array value" + positionvalue, "Enter Number");
string arrayvalues = arrayvalue;
stringsArray[arraypos] = arrayvalues.ToString();
txtOutput.Text += arrayvalues + "\t";
arraypos++;
positionvalue++;
}
mergeSort(stringsArray, 0, stringsArray.Length - 1);
txtOutput.Text += "\r\nSorted array: \r\n";
foreach (string i in stringsArray)
{
txtOutput.Text += i + "\t";
}
}
I think the main problem you are facing while using your sort for string is the below line
if (sortArray[lower] <= sortArray[middle])
Because you cannot use <= on two strings. Rather, what you can do is, you can use the string.CompareTo() method. See the MSDN doc on IComparable for string.
Since you can use that in your code, you can change your code to be like
while ((lower <= lowEnd) && (middle <= upper)) //notice the CompareTo
{
if (sortArray[lower].CompareTo(sortArray[middle]) < 1) //<= here
{
temp[low] = sortArray[lower];
low++;
lower++;
}
else
{
temp[low] = sortArray[middle];
low++;
middle++;
}
}
You might need to adjust your last loop and few other minor stuffs.
for (int i = 0; i < n; i++)
{
sortArray[upper] = temp[upper]; //sortArray is string[]
upper--;
}
Related
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 3 years ago.
I have this Sunday Algorithm, which checks some occurrences in some text.
class Program
{
static int alphabet = 512;
static int[] table = new int[alphabet];
static int[] occurence(string pattern)
{
for(char a = (char)0; a<(char)alphabet;a++)
{
table[(int)a] = -1;
}
for(int i = 0; i< pattern.Length;i++)
{
char a = pattern[i];
table[(int)a] = i;
}
return table;
}
public static int Sunday(string text, string pattern)
{
Stopwatch timer = new Stopwatch();
timer.Start();
int k = 0;
int i = 0;
int[] table = new int[pattern.Length];
table = occurence(pattern);
while(i <= text.Length - pattern.Length)
{
int j = 0;
while(j<pattern.Length && text[i+j] == pattern[j])
{
j++;
}
if(j==pattern.Length)
{
k++;
}
i += pattern.Length;
if(i<text.Length)
{
i -= table[(int)text[i]];
}
}
timer.Stop();
Console.WriteLine(timer.Elapsed);
return k;
}
static void Main(string[] args)
{
string text = File.ReadAllText(#"C:\Users\Bacho\Desktop\Studies\Advanced Algorithms\Test Patterns\Book1.txt");
string pattern = "frankenstein";
Console.WriteLine(Sunday(text, pattern));
}
}
This is my algorithm, which works well on small input of text. In the code, I try to read a text file which consists of roughly 80 000 words and 450 000 characters. I get this exception:
Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Sunday1.Program.Sunday(String text, String pattern) in C:\Users\Bacho\Desktop\Studies\Advanced Algorithms\Sunday1\Sunday1\Program.cs:line 55
at Sunday1.Program.Main(String[] args) in C:\Users\Bacho\Desktop\Studies\Advanced Algorithms\Sunday1\Sunday1\Program.cs:line 68
..at the following line:
i -= table[(int)text[i]];
Is it because it can not fit in string or is it something else?
Changing the algorithm to read and check line by line may be a solution, but is there a way to avoid it?
A char has a length of two bytes or 16 bits not 9. So I guess your alphabet should therefore probably be 65336 or simply char.MaxValue instead of 512.
Also there's no need of the static fields. You can make them local to occurence(). And in Sunday, you don't need to initialize table with new int[pattern.Length], you can directly use occurence(pattern).
class Program
{
static int[] occurence(string pattern)
{
int[] table = new int[char.MaxValue + 1];
for (int a = 0; a < char.MaxValue + 1; a++)
{
table[a] = -1;
}
for (int i = 0; i < pattern.Length; i++)
{
char a = pattern[i];
table[(int)a] = i;
}
return table;
}
public static int Sunday(string text, string pattern)
{
Stopwatch timer = new Stopwatch();
timer.Start();
int k = 0;
int i = 0;
int[] table = occurence(pattern);
while (i <= text.Length - pattern.Length)
{
int j = 0;
while (j < pattern.Length && text[i + j] == pattern[j])
{
j++;
}
if (j == pattern.Length)
{
k++;
}
i += pattern.Length;
if (i < text.Length)
{
i -= table[(int)text[i]];
}
}
timer.Stop();
Console.WriteLine(timer.Elapsed);
return k;
}
static void Main(string[] args)
{
string text = File.ReadAllText(#"C:\Users\Bacho\Desktop\Studies\Advanced Algorithms\Test Patterns\Book1.txt");
string pattern = "frankenstein";
Console.WriteLine(Sunday(text, pattern));
}
}
My goal is to create a score method for a simple game based in an array. The game consists of putting 'R's or 'B's in one of 11 positions in an array. Once the array is full, the score method will execute as follows:
Any single 'R' or 'B' is worth 0 points
Any pair of 'R's or 'B's is worth 4 points
Any triple of 'R's or 'B's is worth 6 points
... and so on.
I'm having trouble calculating the score and I feel like I am missing something obvious so I'm coming here. The code I have looks for pairs and adds 2 to the score, but I end up missing 2 points (since the first pair is worth 4 and each additional "pair" is worth another 2).
public int score(char color)
{
int score = 0;
for (int i = 0; i < gameBoard.Length - 1; i++)
{
if (gameBoard[i] == color && gameBoard[i + 1] == color)
score += 2;
else
score += 0;
}
return score;
}
Your problem can be solved by regular expressions.
public int CalculateScore(char color)
{
var boardStr = String.Join("", gameBoard);
return GetCharacterSequences(color, boardStr)
.Sum(str => str.Length * 2);
}
//Returns same character sequences of length more than two.
private IEnumerable<string> GetCharacterSequences(char color, string boardStr)
{
return Regex.Matches(boardStr, $#"({color})\1+").OfType<Match>()
.SelectMany(match => match.Groups.OfType<Group>())
.Select(#group => #group.Value)
.Where(str => str.Length > 1);
}
Idea of sum function: Each pair costs 4 points, each triple costs 6 points hence each single char costs 2 points.
GetCharacterSequences looks little bit complex but it makes CalculateScore method very simple.
Well you could create a boolean variable and use that to determine the number of points added.
Note: This code doesn't account for triple matches as you've mentioned in your question.
public int score(char color)
{
int score = 0;
bool firstMatch = true;
for (int i = 0; i < gameBoard.Length - 1; i++)
{
if (gameBoard[i] == color && gameBoard[i + 1] == color) {
if (firstMatch == true) {
score += 4;
firstMatch = false;
} else {
score += 2;
}
}
else
{
score += 0;
}
}
return score;
}
Here's another approach, based on a pair being 4 points, 3 being 6 points, and assuming 4 being 8 points and so forth (basically number of adjacent colors * 2 if there is at least a pair).
public int score(char color)
{
int adj = 0;
int score = 0;
for (int i = 0; i < gameBoard.Length; i++)
{
if (gameBoard[i] == color)
{
adj++;
}
else
{
if (adj > 1)
{
score += adj * 2;
}
adj = 0;
}
}
}
This code loops through the array, and keeps a count of the number of adjacent spots marked by the specified color. When it comes to an element of the array that is not the right color, it checks to see how many adjacent elements had the correct color.
If it's greater than 1, then it multiplies the number of adjacent elements by 2 and resets the adjacent elements counter to 0 and continues through the array.
Given an array of 'R', 'R', 'B', 'B', 'B', 'R', 'R', 'R', 'B', 'R', 'B', it produces a score of 10 for 'R' (4 + 6) and 6 for 'B' (6), as follows:
'R', 'R' = 4
'R', 'R', 'R' = 6
'R' = 0
'B', 'B', 'B' = 6
'B' = 0
Here is what i came up with
namespace TestApp1
{
class Program
{
static void Main(string[] args)
{
string[] test = GetValues();
string testView = String.Join(String.Empty, test);
string score = GetScore(test).ToString();
Console.WriteLine(testView);
Console.WriteLine(score);
Console.ReadLine();
}
public static int GetScore(string[] test)
{
int score = 0;
int occurence = 0;
string LastChar = string.Empty;
for (int i = 0; i < test.Length; i++)
{
if(LastChar == string.Empty)
{
LastChar = test[i];
occurence += 1;
continue;
}
if(LastChar == test[i])
{
occurence += 1;
if(i == test.Length - 1)
{
if (occurence > 1)
{
score += occurence * 2;
}
}
}
else
{
if(occurence > 1)
{
score += occurence * 2;
}
LastChar = test[i];
occurence = 1;
}
}
return score;
}
public static string[] GetValues()
{
List<string> values = new List<string>();
for (int i = 0; i < 12; i++)
{
var rnd = new Random(DateTime.Now.Millisecond);
int ticks = rnd.Next(0, 2);
values.Add(ticks == 1 ? "R" : "B");
System.Threading.Thread.Sleep(2);
}
return values.ToArray();
}
}
}
To calculate each score independently
namespace TestApp1
{
class Program
{
static void Main(string[] args)
{
string[] test = GetValues();
string testView = String.Join(String.Empty, test);
int rScore = 0;
int bScore = 0;
GetScore(test,out rScore, out bScore);
string score = "R: " + rScore.ToString() + " B: " + bScore.ToString();
Console.WriteLine(testView);
Console.WriteLine(score);
Console.ReadLine();
}
public static void GetScore(string[] test, out int rScore, out int bScore)
{
int occurence = 0;
string LastChar = string.Empty;
rScore = 0;
bScore = 0;
for (int i = 0; i < test.Length; i++)
{
if(LastChar == string.Empty)
{
LastChar = test[i];
occurence += 1;
continue;
}
if(LastChar == test[i])
{
occurence += 1;
if(i == test.Length - 1)
{
if (occurence > 1)
{
if(LastChar == "R")
{
rScore += occurence * 2;
}
else
{
bScore += occurence * 2;
}
}
}
}
else
{
if(occurence > 1)
{
if (LastChar == "R")
{
rScore += occurence * 2;
}
else
{
bScore += occurence * 2;
}
}
LastChar = test[i];
occurence = 1;
}
}
}
public static string[] GetValues()
{
List<string> values = new List<string>();
for (int i = 0; i < 12; i++)
{
var rnd = new Random(DateTime.Now.Millisecond);
int ticks = rnd.Next(0, 2);
values.Add(ticks == 1 ? "R" : "B");
System.Threading.Thread.Sleep(2);
}
return values.ToArray();
}
}
}
I'm attempting to subtract two strings (of theoretically infinite length) without the use of libraries like BigIntbut I was wondering if anybody has any good ideas on how to remove the leading zeros in the corner cases like the one below?
static void Main(string[] args)
{
Console.WriteLine(Subtract("10", "10005"));
}
static string ReverseInput(string inputString)
{
char[] charArray = inputString.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
static string Subtract(string firstNumInput, string secondNumInput)
{
string firstNum = String.Empty;
string secondNum = String.Empty;
bool negative = false;
// Reverse order of string input
if (firstNumInput.Length > secondNumInput.Length)
{
firstNum = ReverseInput(firstNumInput);
secondNum = ReverseInput(secondNumInput);
}
else if (firstNumInput.Length < secondNumInput.Length)
{
negative = true;
firstNum = ReverseInput(secondNumInput);
secondNum = ReverseInput(firstNumInput);
}
else if (firstNumInput.Length == secondNumInput.Length)
{
// iterate through string to find largest
}
char[] result = new char[firstNum.Length + 1];
int resultLength = 0;
int carry = 0;
for (int i = 0; i < firstNum.Length; i++)
{
int an = (i < firstNum.Length) ? int.Parse(firstNum[i].ToString()) : 0;
int bn = (i < secondNum.Length) ? int.Parse(secondNum[i].ToString()) : 0;
int rn = an - bn - carry;
if (rn < 0)
{
carry = 1;
rn += 10;
}
else
{
carry = 0;
}
result[resultLength++] = (char)(rn + '0');
}
// create the result string from the char array
string finalResult = ReverseInput(new string(result, 0, resultLength));
if (negative)
{
finalResult = '-' + finalResult;
}
return finalResult;
}
Are you looking for TrimStart?
// create the result string from the char array
string finalResult = ReverseInput(new string(result, 0, resultLength)).TrimStart('0');
Is the following 0-1 Knapsack problem solvable:
'float' positive values and
'float' weights (can be positive or negative)
'float' capacity of the knapsack > 0
I have on average < 10 items, so I'm thinking of using a brute force implementation. However, I was wondering if there is a better way of doing it.
This is a relatively simple binary program.
I'd suggest brute force with pruning. If at any time you exceed the allowable weight, you don't need to try combinations of additional items, you can discard the whole tree.
Oh wait, you have negative weights? Include all negative weights always, then proceed as above for the positive weights. Or do the negative weight items also have negative value?
Include all negative weight items with positive value. Exclude all items with positive weight and negative value.
For negative weight items with negative value, subtract their weight (increasing the knapsack capavity) and use a pseudo-item which represents not taking that item. The pseudo-item will have positive weight and value. Proceed by brute force with pruning.
class Knapsack
{
double bestValue;
bool[] bestItems;
double[] itemValues;
double[] itemWeights;
double weightLimit;
void SolveRecursive( bool[] chosen, int depth, double currentWeight, double currentValue, double remainingValue )
{
if (currentWeight > weightLimit) return;
if (currentValue + remainingValue < bestValue) return;
if (depth == chosen.Length) {
bestValue = currentValue;
System.Array.Copy(chosen, bestItems, chosen.Length);
return;
}
remainingValue -= itemValues[depth];
chosen[depth] = false;
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
chosen[depth] = true;
currentWeight += itemWeights[depth];
currentValue += itemValues[depth];
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
}
public bool[] Solve()
{
var chosen = new bool[itemWeights.Length];
bestItems = new bool[itemWeights.Length];
bestValue = 0.0;
double totalValue = 0.0;
foreach (var v in itemValues) totalValue += v;
SolveRecursive(chosen, 0, 0.0, 0.0, totalValue);
return bestItems;
}
}
Yeah, brute force it. This is an NP-Complete problem, but that shouldn't matter because you will have less than 10 items. Brute forcing won't be problematic.
var size = 10;
var capacity = 0;
var permutations = 1024;
var repeat = 10000;
// Generate items
float[] items = new float[size];
float[] weights = new float[size];
Random rand = new Random();
for (int i = 0; i < size; i++)
{
items[i] = (float)rand.NextDouble();
weights[i] = (float)rand.NextDouble();
if (rand.Next(2) == 1)
{
weights[i] *= -1;
}
}
// solution
int bestPosition= -1;
Stopwatch sw = new Stopwatch();
sw.Start();
// for perf testing
//for (int r = 0; r < repeat; r++)
{
var bestValue = 0d;
// solve
for (int i = 0; i < permutations; i++)
{
var total = 0d;
var weight = 0d;
for (int j = 0; j < size; j++)
{
if (((i >> j) & 1) == 1)
{
total += items[j];
weight += weights[j];
}
}
if (weight <= capacity && total > bestValue)
{
bestPosition = i;
bestValue = total;
}
}
}
sw.Stop();
sw.Elapsed.ToString();
If you can only have positive values then every item with a negative weight must go in.
Then I guess you could calculate Value/Weight Ratio, and brute force the remaining combinations based on that order, once you get one that fits you can skip the rest.
The problem may be that the grading and sorting is actually more expensive than just doing all the calculations.
There will obviously be a different breakeven point based on the size and distribution of the set.
public class KnapSackSolver {
public static void main(String[] args) {
int N = Integer.parseInt(args[0]); // number of items
int W = Integer.parseInt(args[1]); // maximum weight of knapsack
int[] profit = new int[N + 1];
int[] weight = new int[N + 1];
// generate random instance, items 1..N
for (int n = 1; n <= N; n++) {
profit[n] = (int) (Math.random() * 1000);
weight[n] = (int) (Math.random() * W);
}
// opt[n][w] = max profit of packing items 1..n with weight limit w
// sol[n][w] = does opt solution to pack items 1..n with weight limit w
// include item n?
int[][] opt = new int[N + 1][W + 1];
boolean[][] sol = new boolean[N + 1][W + 1];
for (int n = 1; n <= N; n++) {
for (int w = 1; w <= W; w++) {
// don't take item n
int option1 = opt[n - 1][w];
// take item n
int option2 = Integer.MIN_VALUE;
if (weight[n] <= w)
option2 = profit[n] + opt[n - 1][w - weight[n]];
// select better of two options
opt[n][w] = Math.max(option1, option2);
sol[n][w] = (option2 > option1);
}
}
// determine which items to take
boolean[] take = new boolean[N + 1];
for (int n = N, w = W; n > 0; n--) {
if (sol[n][w]) {
take[n] = true;
w = w - weight[n];
} else {
take[n] = false;
}
}
// print results
System.out.println("item" + "\t" + "profit" + "\t" + "weight" + "\t"
+ "take");
for (int n = 1; n <= N; n++) {
System.out.println(n + "\t" + profit[n] + "\t" + weight[n] + "\t"
+ take[n]);
}
}
}
import java.util.*;
class Main{
static int max(inta,int b)
{
if(a>b)
return a;
else
return b;
}
public static void main(String args[])
{
int n,i,cap,j,t=2,w;
Scanner sc=new Scanner(System.in);
System.out.println("Enter the number of values ");
n=sc.nextInt();
int solution[]=new int[n];
System.out.println("Enter the capacity of the knapsack :- ");
cap=sc.nextInt();
int v[]=new int[n+1];
int wt[]=new int[n+1];
System.out.println("Enter the values ");
for(i=1;i<=n;i++)
{
v[i]=sc.nextInt();
}
System.out.println("Enter the weights ");
for(i=1;i<=n;i++)
{
wt[i]=sc.nextInt();
}
int knapsack[][]=new int[n+2][cap+1];
for(i=1;i<n+2;i++)
{
for(j=1;j<n+1;j++)
{
knapsack[i][j]=0;
}
}
/*for(i=1;i<n+2;i++)
{
for(j=wt[1]+1;j<cap+2;j++)
{
knapsack[i][j]=v[1];
}
}*/
int k;
for(i=1;i<n+1;i++)
{
for(j=1;j<cap+1;j++)
{
/*if(i==1||j==1)
{
knapsack[i][j]=0;
}*/
if(wt[i]>j)
{
knapsack[i][j]=knapsack[i-1][j];
}
else
{
knapsack[i][j]=max(knapsack[i-1][j],v[i]+knapsack[i-1][j-wt[i]]);
}
}
}
//for displaying the knapsack
for(i=0;i<n+1;i++)
{
for(j=0;j<cap+1;j++)
{
System.out.print(knapsack[i][j]+" ");
}
System.out.print("\n");
}
w=cap;k=n-1;
j=cap;
for(i=n;i>0;i--)
{
if(knapsack[i][j]!=knapsack[i-1][j])
{
j=w-wt[i];
w=j;
solution[k]=1;
System.out.println("k="+k);
k--;
}
else
{
solution[k]=0;
k--;
}
}
System.out.println("Solution for given knapsack is :- ");
for(i=0;i<n;i++)
{
System.out.print(solution[i]+", ");
}
System.out.print(" => "+knapsack[n][cap]);
}
}
This can be solved using Dynamic Programming. Below code can help you solve the 0/1 Knapsack problem using Dynamic Programming.
internal class knapsackProblem
{
private int[] weight;
private int[] profit;
private int capacity;
private int itemCount;
private int[,] data;
internal void GetMaxProfit()
{
ItemDetails();
data = new int[itemCount, capacity + 1];
for (int i = 1; i < itemCount; i++)
{
for (int j = 1; j < capacity + 1; j++)
{
int q = j - weight[i] >= 0 ? data[i - 1, j - weight[i]] + profit[i] : 0;
if (data[i - 1, j] > q)
{
data[i, j] = data[i - 1, j];
}
else
{
data[i, j] = q;
}
}
}
Console.WriteLine($"\nMax profit can be made : {data[itemCount-1, capacity]}");
IncludedItems();
}
private void ItemDetails()
{
Console.Write("\nEnter the count of items to be inserted : ");
itemCount = Convert.ToInt32(Console.ReadLine()) + 1;
Console.WriteLine();
weight = new int[itemCount];
profit = new int[itemCount];
for (int i = 1; i < itemCount; i++)
{
Console.Write($"Enter weight of item {i} : ");
weight[i] = Convert.ToInt32(Console.ReadLine());
Console.Write($"Enter the profit on the item {i} : ");
profit[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
}
Console.Write("\nEnter the capacity of the knapsack : ");
capacity = Convert.ToInt32(Console.ReadLine());
}
private void IncludedItems()
{
int i = itemCount - 1;
int j = capacity;
while(i > 0)
{
if(data[i, j] == data[i - 1, j])
{
Console.WriteLine($"Item {i} : Not included");
i--;
}
else
{
Console.WriteLine($"Item {i} : Included");
j = j - weight[i];
i--;
}
}
}
}
I am trying to get a count of all the times a byte sequences occurs in another byte sequences. It cannot however re-use a bytes if it already counted them. For example given the string
k.k.k.k.k.k. let's assume the byte sequence was k.k it would then find only 3 occurrences rather than 5 because they would be broke down like: [k.k].[k.k].[k.k]. and not like [k.[k].[k].[k].[k].k] where they over lap and essentially just shift 2 to the right.
Ideally the idea is to get an idea how a compression dictionary or run time encoding might look. so the goal would be to get
k.k.k.k.k.k. down to just 2 parts, as (k.k.k.) is the biggest and best symbol you can have.
Here is source so far:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
static class Compression
{
static int Main(string[] args)
{
List<byte> bytes = File.ReadAllBytes("ok.txt").ToList();
List<List<int>> list = new List<List<int>>();
// Starting Numbers of bytes - This can be changed manually.
int StartingNumBytes = bytes.Count;
for (int i = StartingNumBytes; i > 0; i--)
{
Console.WriteLine("i: " + i);
for (int ii = 0; ii < bytes.Count - i; ii++)
{
Console.WriteLine("ii: " + i);
// New pattern comes with refresh data.
List<byte> pattern = new List<byte>();
for (int iii = 0; iii < i; iii++)
{
pattern.Add(bytes[ii + iii]);
}
DisplayBinary(bytes, "red");
DisplayBinary(pattern, "green");
int matches = 0;
// foreach (var position in bytes.ToArray().Locate(pattern.ToArray()))
for (int position = 0; position < bytes.Count; position++) {
if (pattern.Count > (bytes.Count - position))
{
continue;
}
for (int iiii = 0; iiii < pattern.Count; iiii++)
{
if (bytes[position + iiii] != pattern[iiii])
{
//Have to use goto because C# doesn't support continue <level>
goto outer;
}
}
// If it made it this far, it has found a match.
matches++;
Console.WriteLine("Matches: " + matches + " Orig Count: " + bytes.Count + " POS: " + position);
if (matches > 1)
{
int numBytesToRemove = pattern.Count;
for (int ra = 0; ra < numBytesToRemove; ra++)
{
// Remove it at the position it was found at, once it
// deletes the first one, the list will shift left and you'll need to be here again.
bytes.RemoveAt(position);
}
DisplayBinary(bytes, "red");
Console.WriteLine(pattern.Count + " Bytes removed.");
// Since you deleted some bytes, set the position less because you will need to redo the pos.
position = position - 1;
}
outer:
continue;
}
List<int> sublist = new List<int>();
sublist.Add(matches);
sublist.Add(pattern.Count);
// Some sort of calculation to determine how good the symbol was
sublist.Add(bytes.Count-((matches * pattern.Count)-matches));
list.Add(sublist);
}
}
Display(list);
Console.Read();
return 0;
}
static void DisplayBinary(List<byte> bytes, string color="white")
{
switch(color){
case "green":
Console.ForegroundColor = ConsoleColor.Green;
break;
case "red":
Console.ForegroundColor = ConsoleColor.Red;
break;
default:
break;
}
for (int i=0; i<bytes.Count; i++)
{
if (i % 8 ==0)
Console.WriteLine();
Console.Write(GetIntBinaryString(bytes[i]) + " ");
}
Console.WriteLine();
Console.ResetColor();
}
static string GetIntBinaryString(int n)
{
char[] b = new char[8];
int pos = 7;
int i = 0;
while (i < 8)
{
if ((n & (1 << i)) != 0)
{
b[pos] = '1';
}
else
{
b[pos] = '0';
}
pos--;
i++;
}
//return new string(b).TrimStart('0');
return new string(b);
}
static void Display(List<List<int>> list)
{
//
// Display everything in the List.
//
Console.WriteLine("Elements:");
foreach (var sublist in list)
{
foreach (var value in sublist)
{
Console.Write("{0,4}", value);
}
Console.WriteLine();
}
//
// Display total count.
//
int count = 0;
foreach (var sublist in list)
{
count += sublist.Count;
}
Console.WriteLine("Count:");
Console.WriteLine(count);
}
static public int SearchBytePattern(byte[] pattern, byte[] bytes)
{
int matches = 0;
// precomputing this shaves some seconds from the loop execution
int maxloop = bytes.Length - pattern.Length;
for (int i = 0; i < maxloop; i++)
{
if (pattern[0] == bytes[i])
{
bool ismatch = true;
for (int j = 1; j < pattern.Length; j++)
{
if (bytes[i + j] != pattern[j])
{
ismatch = false;
break;
}
}
if (ismatch)
{
matches++;
i += pattern.Length - 1;
}
}
}
return matches;
}
}
Refer to the post to get the non binary of the file should be, here is the binary data:
011010110010111001101011001011100110101100101110011010110010111001101011001011100110101100101110 I am hope to have it smaller than how it started.
private static int CountOccurences(byte[] target, byte[] pattern)
{
var targetString = BitConverter.ToString(target);
var patternString = BitConverter.ToString(pattern);
return new Regex(patternString).Matches(targetString).Count;
}
With this solution you'd have access to the individual indexes that matched (while enumerating) or you could call Count() on the result to see how many matches there were:
public static IEnumerable<int> Find<T>(T[] pattern, T[] sequence, bool overlap)
{
int i = 0;
while (i < sequence.Length - pattern.Length + 1)
{
if (pattern.SequenceEqual(sequence.Skip(i).Take(pattern.Length)))
{
yield return i;
i += overlap ? 1 : pattern.Length;
}
else
{
i++;
}
}
}
Call it with overlap: false to solve your problem or overlap: true to see the overlapped matches (if you're interested.)
I have a couple of other methods with slightly different API (along with better performance) here, including one that work directly on streams of bytes.
quick and dirty with no regex. although i'm not sure if it answers the intent of the question, it should be relatively fast. i think i am going to run some timing tests against regex to see for sure the relative speeds:
private int CountOccurrences(string TestString, string TestPattern)
{
int PatternCount = 0;
int SearchIndex = 0;
if (TestPattern.Length == 0)
throw new ApplicationException("CountOccurrences: Unable to process because TestPattern has zero length.");
if (TestString.Length == 0)
return 0;
do
{
SearchIndex = TestString.IndexOf(TestPattern, SearchIndex);
if (SearchIndex >= 0)
{
++PatternCount;
SearchIndex += TestPattern.Length;
}
}
while ((SearchIndex >= 0) && (SearchIndex < TestString.Length));
return PatternCount;
}
private void btnTest_Click(object sender, EventArgs e)
{
string TestString1 = "k.k.k.k.k.k.k.k.k.k.k.k";
string TestPattern1 = "k.k";
System.Console.WriteLine(CountOccurrences(TestString1, TestPattern1).ToString()); // outputs 6
System.Console.WriteLine(CountOccurrences(TestString1 + ".k", TestPattern1).ToString()); // still 6
System.Console.WriteLine(CountOccurrences(TestString1, TestPattern1 + ".").ToString()); // only 5
}