So am working on a text mining project and currently trying to implement info gain. I have a data in which each line depict a document. so a new line character splits different documents.
i have to generate a matrix in which columns are all the distinct words in all documents and rows are different document. each cell in this table is either 1(true) or 0(false) for if the word is present or not in that document.
there are 987 documents, total words are 22860 and total distinct words are 3680. so 3680 words are compared with 22860. this is running slow but am fine with it. The loop that is taking more time is when i traverse through the objects of list of words to generate matrix. see below
Note: i have removed all repeated words in a document already.
class word_list
{
public string word;
public List<bool> doc= new List<bool>();
};//class ends
private void button2_Click(object sender, EventArgs e)
{
//Convert the string into an array of words
string[] w1 = richTextBox1.Text.Trim().Split('\n',' ').Select(x => x.Trim().ToLower()).Distinct().ToArray(); //all distinct words
string[] rich_doc = richTextBox1.Text.Trim().Split('\n'); //all documents array
List<word_list> words = new List<word_list>();
richTextBox2.Text+=("no. of distict words: " + w1.Length + ", no. of docs " + rich_doc.Length);
for (int i = 0; i < w1.Length; i++)
{
word_list temp = new word_list();
temp.word = w1[i]; //temp has the current distict word as class object
for(int j=0;j<rich_doc.Length;j++)//traverse all doc array
{
temp.doc.Add(false);
List<string> doc_word = Regex.Split(rich_doc[j], #"\b").Distinct(StringComparer.CurrentCultureIgnoreCase).ToList();
//richTextBox2.Text += ("\n no. of words in this doc: " + doc_word.Count);
//richTextBox2.SelectionStart = richTextBox1.Text.Length;
//richTextBox2.Focus();
int doc_count = doc_word.Count; // number of docs
for (int k = 0; k < doc_count; k++)//All words in a doc are compared
{
if(doc_word[k].ToLower() == w1[i].ToLower())
{
temp.doc[temp.doc.Count-1]=true;
break;
}
}
}
if ((words.Count - 1)>=0)
richTextBox2.Text += ("\n word(" + words.Count + "/" + w1.Length + "): " + words[words.Count - 1].word);
richTextBox2.SelectionStart = richTextBox1.Text.Length;
richTextBox2.Focus();
words.Add(temp);
}
//generate matrix
int t = rich_doc.Length; //no. of docs
int word_count = words.Count;
richTextBox1.Text = "Doc";
foreach (word_list w in words)
{
richTextBox1.Text += "\t" + w.word;
}
richTextBox1.Text += "\n";
//This loop is slow
for (int i = 0; i < t; i++) //traverse through number of docs
{
richTextBox1.Text += i + 1;
for (int h = 0; h < word_count; h++)//traverse through each distinct word in the list
{
if (words[h].doc[i])
richTextBox1.Text += "\t1";
else
richTextBox1.Text += "\t0";
}
richTextBox1.Text += "\n";
}
}//end of button 2
ta.speot.is is correct. Strings are supposed to be built with StringBuilder, using Append for instance, and only after the loop you assign the string to richTextBox1.Text. The code would look like this:
//generate matrix
StringBuilder sb = new StringBuilder();
int t = rich_doc.Length; //no. of docs
int word_count = words.Count;
richTextBox1.Text = "Doc";
foreach (word_list w in words)
{
sb.Append("\t");
sb.Append(w.word);
}
sb.AppendLine();
//This loop is not slow anymore :)
for (int i = 0; i < t; i++) //traverse through number of docs
{
sb.Append(i + 1);
for (int h = 0; h < word_count; h++)//traverse through each distinct word in the list
{
if (words[h].doc[i])
sb.Append("\t1");
else
sb.Append("\t0");
}
sb.AppendLine();
}
richTextBox1.Text = sb.ToString();
EDIT: There are valuable comments below. Changing RichEditBox.Text property is the most expensive operation here.
Related
for (int i = 0; i < CheckBoxList3.Items.Count + 1; i++)
{
if (CheckBoxList3.Items[i].Selected || CheckBoxList4.Items[i].Selected || CheckBoxList5.Items[i].Selected)
{
str1 += CheckBoxList3.Items[i].Text.ToString() + "," + CheckBoxList4.Items[i].Text.ToString() +"," + CheckBoxList5.Items[i].Text.ToString() + ",";
I receive the error call "Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index". How to solve this issue?
What I want to do was collect the data from checkedbox in multiple check-box-list and combine together and store it into database.
Any suggestion or help would be great. Thanks
UPDATE : This is one of my check box list. The error point to my second line of the for loop.
<asp:CheckBoxList ID="CheckBoxList3" runat="server" RepeatDirection="Horizontal" Width="900px">
<asp:ListItem>Chicken</asp:ListItem>
<asp:ListItem>Tomato</asp:ListItem>
<asp:ListItem>Garlic</asp:ListItem>
</asp:CheckBoxList>
Wrong line 1: for (int i = 0; i < CheckBoxList3.Items.Count + 1; i++
Wrong line 2: CheckBoxList3.Items[i].Selected || CheckBoxList4.Items[i].Selected || CheckBoxList5.Items[i].Selected
Wrong line 3: str1 += CheckBoxList3.Items[i].Text.ToString() + "," + CheckBoxList4.Items[i].Text.ToString() +"," + CheckBoxList5.Items[i].Text.ToString() + ",";
You need to change your for loop condition from CheckBoxList3.Items.Count + 1 to CheckBoxList3.Items.Count
Also your condition checking only CheckBoxList3.Items.Count but you are using CheckBoxList4.Items.Count and CheckBoxList5.Items.Count
It seems CheckBoxList4 and CheckBoxList5 don't have enough item like CheckBoxList3.
Please Check your all individual CheckboxList objects to use same indexer.
Hope this helps.
//EDIT
Best practice:
string result = CombineCheckboxLists(checkBoxList1, checkBoxList2, checkboxlist3);
private string CombineCheckboxLists(params CheckBoxList[] list)
{
StringBuilder builder = new StringBuilder();
string result = string.Empty;
if (list?.Length > 0)
{
int minItemsCount = list.Min(l => l.Items.Count);
if (minItemsCount > 0)
{
for (int i = 0; i < minItemsCount; i++)
{
builder.Append(string.Join(",", list
.Where(l => l.Items[i].Selected)
.Select(l=> l.Items[i].Text)));
//if you want to merge all iteration via ",", please use following lines instead of above -- [marked as **]
// ** //builder.Append($"{string.Join(",", list.Select(l => l.Items[i].Value))},");
}
}
}
result = builder.ToString();
// ** // result = result.TrimEnd(',');
return result;
}
Just change your for loop like below:
for (int i = 0; i < CheckBoxList3.Items.Count; i++)
if (CheckBoxList3.Items[i].Selected)
str1 += CheckBoxList3.Items[i].Text.ToString() + ",";
for (int i = 0; i < CheckBoxList4.Items.Count; i++)
if (CheckBoxList4.Items[i].Selected)
str1 += CheckBoxList4.Items[i].Text.ToString() + ",";
for (int i = 0; i < CheckBoxList5.Items.Count; i++)
if (CheckBoxList5.Items[i].Selected)
str1 += CheckBoxList5.Items[i].Text.ToString() + ",";
UPDATE
#Caner LENGER has a good idea. But as I mentioned in the comment of his answer it's partially true, because list.Min returns minimum value of a list that in your case it's not gonna work. Why?
Imagine you have 3 CheckBoxLists that each one has 3 items in it except one of them that has 4. Using list.Min you'll get 3, No matter what's inside the 4th value of CheckBoxList.
So, I changed his code and here is the tested result:
public static string CombineCheckboxLists(params CheckBoxList[] list)
{
StringBuilder sb = new StringBuilder();
foreach (CheckBoxList checkBoxList in list)
{
int counter = checkBoxList.Items.Count;
for (int i = 0; i < counter; i++)
sb.Append(checkBoxList.Items[i].Selected ? checkBoxList.Items[i].Text + "," : "");
}
return sb.ToString();
}
I have a List of 9 integers and I want to print all elements from the list as a matrix 3,3. And I have to avoid unnecessary white space on the end of every line.
Is it possible to use String.Join ?
Thanks.
Here's my code:
int[] input = Console.ReadLine().Split().Select(int.Parse).ToArray();
int[][] matrix = new int[input[0]][];
for (int i = 0; i < input[0]; i++)
{
int[] line = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
matrix[i] = line;
}
List<int> arr = new List<int>(9);
List<int> arr1 = new List<int>(9);
arr = Enumerable.Repeat(0, 9).ToList();
//for (int i = 0; i < 9 ; i++) sum[i%3, i/3] = 0;
for (int row = 0; row < input[0] - 2; row++)
{
for (int col = 0; col < input[1] - 2; col++)
{
arr1.Add(matrix[row][col]);
arr1.Add(matrix[row][col + 1]);
arr1.Add(matrix[row][col + 2]);
arr1.Add(matrix[row + 1][col]);
arr1.Add(matrix[row + 1][col + 1]);
arr1.Add(matrix[row + 1][col + 2]);
arr1.Add(matrix[row + 2][col]);
arr1.Add(matrix[row + 2][col + 1]);
arr1.Add(matrix[row + 2][col + 2]);
if (arr1.Sum() > arr.Sum())
{
arr = arr1.Select(a => a).ToList();
}
arr1.Clear();
}
}
Console.WriteLine($"Sum = {arr.Sum()} ");
// print the list as a matrix
This is how I would print it using String.Join:
List<int> asd = new List<int> {1,2,3,4,5,6,7,8,9};
for (int i = 0; i < asd.Count; i +=3)
{
Console.WriteLine(string.Join(" ",asd.Skip(i).Take(3)));
}
Explanation: Walk in steps of 3. Skip the amount of numbers equal to the stepsize and take 3 to combine a row of the matrix.
You should reconsider the accepted answer because the performance is poorly with many items.
It may be irrelevant for your current count of items but still hear my warning.
I ran the following code snippet:
var sb = new StringBuilder();
for (int i = 0; i < asd.Count; i +=3)
sb.AppendLine(string.Join(" ", asd.Skip(i).Take(3)));
Console.WriteLine(sb.ToString());
used a StringBuilder to remove the time relevant Console.WriteLine(); for every item in the loop.
This approach takes 756,115ms to complete, with 1,000,000 items.
Created the asd list like this:
var asd = Enumerable.Range(0, 1000000).ToList();
Every other answer given so far will perform way better.
The reason why the accepted solution performs this poorly is because of the .Skip() that is getting called inside the loop, it doesn't actually skip and go directly to this Position instead it again and again loops the list till it reaches this point.
My solution would be:
Console.WriteLine(string.Concat(asd.Select((x, i) => (i + 1) % 3 != 0 ? x + " " : x + Environment.NewLine)));
Which executes the same task in 8,610ms
For completness:
Wojtek's solution takes: 7,932ms
Nirmal Subedi' solution takes: 8,088ms
Note:
Changed it so that it uses a StringBuilder to build the string and only output the string once to the console, instead of calling Console.WriteLine() in a loop
Here my complete test routine:
var asd = Enumerable.Range(0, 1000000).ToList();
var sw1 = new Stopwatch();
sw1.Start();
Console.WriteLine(string.Concat(asd.Select((x, i) => (i + 1) % 3 != 0 ? x + " " : x + Environment.NewLine)));
sw1.Stop();
var sw2 = new Stopwatch();
sw2.Start();
var sb1 = new StringBuilder();
for (int i = 0; i < asd.Count; i += 3)
sb1.AppendLine(string.Join(" ", asd.Skip(i).Take(3)));
Console.WriteLine(sb1.ToString());
sw2.Stop();
var sw3 = new Stopwatch();
sw3.Start();
var sb2 = new StringBuilder();
int counter = 0;
string output = "";
foreach (int value in asd)
{
counter++;
if (counter % 3 == 0)
{
output += value;
sb2.AppendLine(output);
output = string.Empty;
}
else
output += value + " ";
}
Console.WriteLine(sb2.ToString());
sw3.Stop();
var sw4 = new Stopwatch();
sw4.Start();
var sb3 = new StringBuilder();
for (int i = 0; i <asd.Count / 3; i++)
{
int index = i * 3;
sb3.AppendFormat("{0} {1} {2}", asd[index], asd[index + 1], asd[index + 2]);
sb3.AppendLine();
}
Console.WriteLine(sb3.ToString());
sw4.Stop();
Console.WriteLine("MySolution: " + sw1.ElapsedMilliseconds);
Console.WriteLine("Mong Zhu's Solution: " + sw2.ElapsedMilliseconds);
Console.WriteLine("Wojtek's Solution: " + sw3.ElapsedMilliseconds);
Console.WriteLine("Nirmal Subedi's Solution: " + sw4.ElapsedMilliseconds);
Console.ReadKey();
Now You have your code pasted. Anyway, I created the sample to print the 3x3 matrix.
class Program
{
static void Main(string[] args)
{
StringBuilder stringBuilder = new StringBuilder();
List<int> numbers = new List<int>() {1,2,3,4,5,6,7,8,9 };
for (int i = 0; i <3; i++)
{
int index = i * 3;
stringBuilder.AppendFormat("{0}{1}{2}", numbers[index], numbers[index + 1], numbers[index + 2]);
stringBuilder.AppendLine();
}
Console.Write(stringBuilder.ToString());
Console.ReadLine();
}
}
Is that what you meant?
string output = string.Empty;
List<int> myList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int counter = 0;
foreach (int value in myList)
{
output += value.ToString();
counter++;
if (counter % 3 == 0)
{
Console.WriteLine(output);
output = string.Empty;
}
}
I want to split a string into multiple strings based on the following criteria:
It has to be minimum 2 words together
Each word must be next to each other
For example:
"hello how are you" I want to split into:
"hello how are you"
"hello how are"
"hello how"
"how are"
"how are you"
"are you"
Can't repeat multiple times.
What I got so far is this:
string input = "hello how are you";
List<string> words = input.Split(' ').ToList();
List<string> inputs = new List<string>();
string temp = String.Empty;
for (int i = 0; i < words.Count; i++)
{
temp += words[i] + " ";
if (i > 0)
{
inputs.Add(temp);
}
}
It outputs the following:
hello how
hello how are
hello how are you
I want to get the others too and need a little help with that.
One approach would be to iterate over each word and get all its possible sequences.
Example:
string input = "hello how are you";
List<string> words = input.Split(' ').ToList();
List<string> inputs = new List<string>();
for (int i = 0; i < words.Count; i++)
{
var temp = words[i];
for(int j = i+1;j < words.Count;j++) {
temp += " " + words[j];
inputs.Add(temp);
}
}
//hello how
//hello how are
//hello how are you
//how are
//how are you
//are you
Here's the pseudocode
for (int i = 0; i < words.Count - 1; i++)
{
for each (int j = i + 1; j < words.Count; j++)
{
//rebuild string from words[i] through words[j] and add to list
}
}
The idea is to consider each word except the last as a starting word (since it can't have a words following it). For starting word, consider each possible ending word (the first would be the next word in the list and the last would be the last word). Then for each starting/ending word pair, rebuild the string out of all the words in between, and add it to the list
I want to generate 1000 number randomly and put the result in a rich text box ,but the result I got from my code is just one number appearing in the rich text box !!
private Random _random = new Random();
int min = 000000;
int max = 999999;
string s;
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 1000; i++)
{
s = _random.Next(min, max).ToString("D6") + "\n";
}
richTextBox1.Text = s;
}
You are overriding the value of s each time you get your next number. Instead you have to add the number to a list. Something like this would work.
List<string> numbers = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 1000; i++)
{
numbers.Add(_random.Next(min, max).ToString("D6"));
}
richTextBox1.Text = string.Join(Environment.NewLine, numbers);
}
As most of the answers here using the .net class Random i would not use it, because in a direct comparison it doesn't creates strong random numbers.
Example:
So if you want strong random numbers you should refrain from using Random and use the RNGCryptoServiceProvider from the namesapace System.Security.Cryptography
ExampleCode:
private RNGCryptoServiceProvider _random = new RNGCryptoServiceProvider ();
int min = 000000;
int max = 999999;
private void Form1_Load(object sender, EventArgs e)
{
int[] results = new int[1000];
var buffer = new byte[4];
int min = 100000;
int max = 999999;
for (int i = 0; i < results.Length; i++) {
while(results[i] < min || results[i] > max)
{
_random.GetBytes(buffer);
results[i] = BitConverter.ToInt32(buffer, 0);
}
richTextBox1.Text += results[i].toString();
}
}
You actually need to concatenate the result with previous calculated result, right now it is replacing the string value in s every time loop executes and you end up only with the last value in s, a quick fix is to use contatination using +:
for (int i = 0; i < 1000; i++)
{
s+= _random.Next(min, max).ToString("D6") + "\n"; // now it keeps previous values as well
}
Problem is that you actually overwrite at each iteration the string s. You need to append the number to the old ones.
for (int i = 0; i < 1000; i++)
{
s += _random.Next(min, max).ToString("D6") + "\n";
}
richTextBox1.Text = s;
You could also use AppendText method
for (int i = 0; i < 1000; i++)
{
richTextBox1.AppendText(_random.Next(min, max).ToString("D6") + "\n");
}
Suggestion by Matthew Watson: When generating such a large string it is very adviseable to use a StringBuilder. Is has much better performance than a normal concatenation of strings:
StringBuilder sb = new StringBuilder(8000);
for (int i = 0; i < 1000; i++)
{
sb.AppendLine(_random.Next(min, max).ToString("D6"));
}
richTextBox1.Text = sb.ToString();
s += _random.Next(min, max).ToString("D6") + "\n";
^
|
---- You're missing this plus sign
on this line of code you override the Text of richTextBox1
for (int i = 0; i < 1000; i++)
{
s = _random.Next(min, max).ToString("D6") + "\n";
}
richTextBox1.Text = s;
just change it to (add a + after s)
for (int i = 0; i < 1000; i++)
{
s += _random.Next(min, max).ToString("D6") + "\n";
}
richTextBox1.Text = s;
Note that the maxValue or Random.Next is exclusive, so 999999 is never genereted.
var numbers = Enumerable.Repeat(new Random(), 1000)
.Select(r => r.Next(1000000).ToString("D6")); // the same new Random() instance is used for all .Next
richTextBox1.Text = string.Join("\r\n", numbers);
Or a bit more efficient:
richTextBox1.Text = Enumerable.Repeat(new Random(), 1000).Aggregate(new StringBuilder(7000)
, (b, r) => b.AppendFormat("{0:D6}\n", r.Next(1000000))).ToString(0, 6999);
just You need to add ' + ' for the richtextbox1 as like below
try this one
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 1000; i++)
{
s = _random.Next(min, max).ToString("D6") + "\n";
richTextBox1.Text + = s;
}
}
So I'm new to working with browsers in Win-forms and I'm stuck a particular point.
What i want to do, for the browser to open a page(I've gotten this far). Once the page is open it must navigate to a particular part(It'somewhere in the middle of the page) and select it. Then copy and store it for when i need it, just the text.
I've been able to select all the text on a page by using the following code just as an example:
WebBrowser wb = (WebBrowser)sender;
wb.Document.ExecCommand("SelectAll", false, null);
wb.Document.ExecCommand("Copy", false, null);
richTextBox1.Text = Clipboard.GetText();
It can work for my program but I want to know if there is better way that will select just the text or info I need. If i can, place them in textboxes, or straight into my database.
This is the link to the page: http://www.lolking.net/news/league-trends-jul30
I want to select and get the info from these sections of the page:
Champion Pick Rates - Top 5 Increases and Decreases
Champion Win Rates - Top 5 Increases and Decreases
Champion Ban Rates - Top 5 Increases and Decreases
Any help would be appreciated.
Your foreach loop will look like this:
foreach (var item in list_ban)
{
string rtbpicker = item.ToString();
foreach (var comp in list_Comp)
{
int count = 0; //Counts for the number of occurences
foreach (Match m in Regex.Matches(rtbpicker, "" + comp.ToString() + ""))
{
int matchindex = m.Index;
int matchlength = m.Length;
rtbpicker = rtbpicker.Insert(matchindex + matchlength + count, " "); //Count just moves the index forward by however many postions the original index was shifted
if(Regex.Matches(rtbpicker, "" + comp.ToString() + "").Count > 1)
{
count++;
}
}
}
richTextBox6.Text += rtbpicker + "\n";
//rtbBan.AppendText(rtbpicker + System.Environment.NewLine);
}
I haven't got (yet) the whole solution but I can help you a bit:
Once you got the plain text from the FULLY LOADED webBrowser, and wrote in richTextBox1, then you can print the 3 part to other textboxes:
private void button_Click(object sender, EventArgs e)
{
List<string> rawhtml = new List<string>(); //List for the whole page
List<string> list_pick = new List<string>(); //PICK section
List<string> list_win = new List<string>(); //WIN section
List<string> list_ban = new List<string>(); //BAN section
rawhtml = richTextBox1.Lines.ToList(); //FILL the page to list
int ID_pick = 0;
int ID_win = 0;
int ID_ban = 0;
int ID_cmt = 0; // We need to specify the end of BAN section
for (int i = 0; i < rawhtml.Count; i++) //Search for the line number of section-start
{
if (rawhtml[i] == "Champion Pick Rates") ID_pick = i;
if (rawhtml[i] == "Champion Win Rates") ID_win = i;
if (rawhtml[i] == "Champion Ban Rates") ID_ban = i;
if (rawhtml[i].Contains("Comments")) ID_cmt = i;
}
// PICK
for (int i = ID_pick; i < ID_pick + (ID_win - ID_pick); i++) //Calculate the start and the end line-number
{
list_pick.AddRange(Regex.Split(rawhtml[i], "(?<=[)])")); //Split the five characters, without losing the ')'
}
foreach (var item in list_pick)
{
richTextBox2.AppendText(item + System.Environment.NewLine); //Optinal: Add to richtextbox
}
// WIN
for (int i = ID_win; i < ID_win + (ID_ban - ID_win); i++)
{
list_win.AddRange(Regex.Split(rawhtml[i], "(?<=[)])"));
}
foreach (var item in list_win)
{
richTextBox3.AppendText(item + System.Environment.NewLine);
}
// BAN
for (int i = ID_ban; i < ID_ban + (ID_cmt - ID_ban); i++)
{
list_ban.AddRange(Regex.Split(rawhtml[i], "(?<=[)])"));
}
foreach (var item in list_ban)
{
richTextBox4.AppendText(item + System.Environment.NewLine);
}
}
This code will make output from "Champion Win Rates" like:
Champion Win Rates
Top Five Biggest Increases
Urgot41.38%->43.67%(+2.29%)
Kennen47.7%->49.28%(+1.58%)
Lucian51.61%->53.1%(+1.49%)
Singed48.95%->50.31%(+1.36%)
Fiora53.48%->54.71%(+1.23%)
Top Five Biggest Decreases
Kassadin48.7%->46.67%(-2.03%)
Galio53.18%->51.42%(-1.76%)
Cho'Gath48.03%->46.37%(-1.66%)
Corki50.05%->48.43%(-1.62%)
Graves49.49%->47.98%(-1.51%)
Much better... ;)
I'm faced a problem with spaces, but i can't solve it yet.
I hope you understand this, if you have any question please comment!
Ps.: Sorry for bad eng
Pss.: I know this isn't the full solution, but i must share with you :)
And now the full solution, with perfect spaces. Regex was difficult to me, but I think this is more simple, however longer too.
private void btnspace_Click(object sender, EventArgs e)
{
richTextBox6.Text = null;
for (int i = 0; i < list_ban.Count; i++)
{
string rebuilder = ""; //for the output string (one line)
List<char> temp_chars = list_ban[i].ToCharArray().ToList(); //split one line into char sequence
int number_occur = 0; //occurence counter for numbers
int minus_occur = 0;// occurence counter for '-'
for (int j = 0; j < temp_chars.Count; j++)
{
// NUMBERS
// I don't wanted to hardcode the champions :/
if (number_occur < 2 && (temp_chars[j] == '1' || temp_chars[j] == '2' || temp_chars[j] == '3' || temp_chars[j] == '4' || temp_chars[j] == '5' || temp_chars[j] == '6' || temp_chars[j] == '7' || temp_chars[j] == '8' || temp_chars[j] == '9' || temp_chars[j] == '0')) //looks pretty, isn't?
{
temp_chars.Insert(j, ' '); //insert a space into char seq
j = j + 5; // in the longest case: 12.34, so skip 5 char, or 1 2. 3 4
number_occur = number_occur + 1; //for the difference percentage we don't need spaces, so insert by number only twice
}
// NUMBERS DONE
}
for (int j = 0; j < temp_chars.Count; j++)
{
// ( and -
if (temp_chars[j] == '-' || temp_chars[j] == '(')
{
if (temp_chars[j] == '-') minus_occur = minus_occur + 1; //if the difference is negative, there will be one more minus, which doesn't need space
if (minus_occur <= 1) temp_chars.Insert(j, ' ');
j = j + 1; //avoid endless loop
}
// ( and - DONE
}
foreach (var item in temp_chars)
{
rebuilder = rebuilder + item; //rebuild the line from the char list, with spaces
}
list_ban.RemoveAt(i); //replace the old spaceless lines...
list_ban.Insert(i, rebuilder);
richTextBox1.AppendText(list_ban[i] + System.Environment.NewLine);
}
}
I hope it's clear, i tried to comment everything. Good luck, and feel free to ask. Please mention if it's working because i want to answer this question perfectly :D
Ok, so this is my final solution, it works 100%, it takes your first answer, which you can see ;p and uses my regex.matches. I think the part that i added to the foreach loops, could be done in a method so you can just call it whenever you need it. I just haven't got to that yet! :)
private void button3_Click(object sender, EventArgs e)
{
List<string> rawhtml = new List<string>(); //List for the whole page
List<string> list_pick = new List<string>(); //PICK section
List<string> list_win = new List<string>(); //WIN section
List<string> list_ban = new List<string>(); //BAN section
List<string> list_Comp = new List<string>(); //Champion names
fillchamplist(list_Comp);
rawhtml = richTextBox1.Lines.ToList(); //FILL the page to list
int ID_pick = 0;
int ID_win = 0;
int ID_ban = 0;
int ID_cmt = 0; // We need to specify the end of BAN section
for (int i = 0; i < rawhtml.Count; i++) //Search for the line number of section-start
{
if (rawhtml[i] == "Champion Pick Rates") ID_pick = i;
if (rawhtml[i] == "Champion Win Rates") ID_win = i;
if (rawhtml[i] == "Champion Ban Rates") ID_ban = i;
if (rawhtml[i].Contains("Comments")) ID_cmt = i;
}
// PICK
for (int i = ID_pick; i < ID_pick + (ID_win - ID_pick); i++) //Calculate the start and the end line-number
{
list_pick.AddRange(Regex.Split(rawhtml[i], "(?<=[)])")); //Split the five characters, without losing the ')'
}
foreach (var item in list_pick)
{
string rtbpicker = item.ToString();
foreach (var comp in list_Comp)
{
int count = 0; //To see which match we working with later
foreach (Match m in Regex.Matches(rtbpicker, "" + comp.ToString() + "")) // Checks for all matches and cycles through them
{
if (count == 2) // if the count == 2, it means that its on its 3rd match(the one we dont wana give a space to
{
}
else // puts the space in
{
int matchindex = m.Index;
int matchlength = m.Length;
if (m.Length >= 2) // only champ names are >=2
{
rtbpicker = rtbpicker.Insert(matchindex + matchlength + count, "\t");
}
else
{
rtbpicker = rtbpicker.Insert(matchindex + matchlength + count, " "); // the count variable updates he index so the space doesnt occur before the % sign
}
if (Regex.Matches(rtbpicker, "" + comp.ToString() + "").Count > 0)// just to update the index for the 2nd %
{
count++;
}
}
}
}
rtbPick.AppendText(rtbpicker + System.Environment.NewLine); //Optinal: Add to richtextbox
}
// WIN
for (int i = ID_win; i < ID_win + (ID_ban - ID_win); i++)
{
list_win.AddRange(Regex.Split(rawhtml[i], "(?<=[)])"));
}
foreach (var item in list_win)
{
string rtbpicker = item.ToString();
foreach (var comp in list_Comp)
{
int count = 0;
foreach (Match m in Regex.Matches(rtbpicker, "" + comp.ToString() + ""))
{
if (count == 2)
{
}
else
{
int matchindex = m.Index;
int matchlength = m.Length;
if (m.Length >= 2)
{
rtbpicker = rtbpicker.Insert(matchindex + matchlength + count, "\t");
}
else
{
rtbpicker = rtbpicker.Insert(matchindex + matchlength + count, " ");
}
if (Regex.Matches(rtbpicker, "" + comp.ToString() + "").Count > 0)
{
count++;
}
}
}
}
rtbWin.AppendText(rtbpicker + System.Environment.NewLine);
}
// BAN
for (int i = ID_ban; i < ID_ban + (ID_cmt - ID_ban); i++)
{
list_ban.AddRange(Regex.Split(rawhtml[i], "(?<=[)])"));
}
foreach (var item in list_ban)
{
string rtbpicker = item.ToString();
foreach (var comp in list_Comp)
{
int count = 0;
foreach (Match m in Regex.Matches(rtbpicker, "" + comp.ToString() + ""))
{
if (count == 2)
{
}
else
{
int matchindex = m.Index;
int matchlength = m.Length;
if (m.Length >= 2)
{
rtbpicker = rtbpicker.Insert(matchindex + matchlength + count, "\t");
}
else
{
rtbpicker = rtbpicker.Insert(matchindex + matchlength + count, " ");
}
if (Regex.Matches(rtbpicker, "" + comp.ToString() + "").Count > 0)
{
count++;
}
}
}
}
rtbBan.AppendText(rtbpicker + System.Environment.NewLine);
}
}
This is the outcome:(doesn't show the tabs here for some reason)
Champion Pick Rates
Top Five Biggest Increases
Lucian 27.75% -> 32.3% (+4.55%)
Ahri 8.7% -> 11.3% (+2.6%)
Rengar 11.25% -> 13.84% (+2.59%)
Nidalee 10.7% -> 12.93% (+2.23%)
Tristana 30.07% -> 32.02% (+1.95%)
Top Five Biggest Decreases
Caitlyn 34.44% -> 30.63% (-3.81%)
Vayne 17.25% -> 15.69% (-1.56%)
Ezreal 15.08% -> 13.6% (-1.48%)
Renekton 13.84% -> 12.6% (-1.24%)
Lee Sin 30.54% -> 23.36% (-7.18%)
Ok so :D that works perfect for me, but that's cause i know what i want the outcome to be for this specific thing. Your method also works and i would actually recommend it for scenarios.
If you got any questions, dont be afraid to ask hey :)