Counting occurrences in Array - c#

I am counting the occurrence of each element in the array but I get the error "Value cannot be null" This doesn't make sense to me because arr1 is fully populated with no null values except the last 5 elements which are null.
Here is my code. I am using dictionary for the first time so I may have some logic error somewhere. I am reading from a textfile.
string[] arr1 = new string[200];
StreamReader sr = new StreamReader("newWorkSheet.txt");
string Templine1 = "";
int counter = 0;
while (Templine1 != null)
{
Templine1 = sr.ReadLine();
arr1[counter] = Templine1;
counter += 1;
}
sr.Close();
// Dictionary, key is number from the list and the associated value is the number of times the key is found
Dictionary<string, int> occurrences = new Dictionary<string, int>();
// Loop test data
foreach (string value in arr1)
{
if (occurrences.ContainsKey(value)) // Check if we have found this key before
{
// Key exists. Add number of occurrences for this key by one
occurrences[value]++;
}
else
{
// This is a new key so add it. Number 1 indicates that this key has been found one time
occurrences.Add(value, 1);
}
}
// Dump result
System.IO.StreamWriter sr2 = new System.IO.StreamWriter("OrganizedVersion.txt");
foreach (string key in occurrences.Keys)
{
sr2.WriteLine("Integer " + key.ToString() + " was found " + occurrences[key].ToString() + " times");
}
sr2.Close();
Console.ReadLine();
Edit: I put all the code here including declaration.

It's not exactly your question but Linq could reduce the number of lines here:
var groups = arr1.GroupBy(item => item);
foreach (var group in groups)
{
Console.WriteLine(string.Format("{0} occurences of {1}", group.Count(), group.Key);
}

My money is on arr1 being null (based on the fact that you should know the size beforehand but you're filling with lines from a file that could possibly change). The good thing is that you don't actually need it.
Replace this: foreach (string value in arr1)
... with this:
foreach(string value in File.ReadLines("fileName"))
{
}
MSDN File.ReadLines

"arr1 is fully populated with no null values"
Nope. The last item that you put in the array is null. Check the value before you put it in the array:
while (true) {
Templine1 = sr.ReadLine();
if (Templine1 == null) break;
arr1[counter++] = Templine1;
}
Or if you like this method better:
while ((Templine1 = sr.ReadLine()) != null) {
arr1[counter++] = Templine1;
}
Now, loop up to the index counter, instead of looping through the entire array regardless of how many items you put in it:
for (int i = 0; i < counter; i++) {
string value = arr1[i];
...
}

In your loop you need to check if there is null in your value
foreach (string value in arr1)
{
if (!string.IsNullOrEmpty(value))
{
........
This will take care of problems you might have in the file.

Related

How to get data out of a foreach and reuse in while and do while in c#?

In the Foreach the data has loop exactly but when the data send to while, It display single character only of each data for example: exact data is: "John" but in my code it display: J then next O, H, N until each character of the exact data is finished. Code example below:
foreach (DataGridViewRow row in DataGrid2.Rows)
{
bool isSelected = Convert.ToBoolean(row.Cells["ChkOkay"].Value);
if (isSelected)
{
value += row.Cells["EnrollName"].Value.ToString();
Console.Writeline("Selected Values " + value);
}
}
while (v < value.Length())
{
do
{
//It display single character only instead whole name.
MessageBox.Show("Name: "value[v] + "Slot: " + u);
foreach (var chari in value[v].ToString())
{
//I re use the data here from 1st foreach
}
v++;
u += 51;
} while (u < 5559);
I did not understand your code, but the correct form is to take a column of DataGrid rows and place it in a list.
You then print the list elements and then check the characters of each list item.
List<string> EnrollNameList = new List<string>();
foreach (DataGridViewRow row in DataGrid2.Rows)
{
bool isSelected = Convert.ToBoolean(row.Cells["ChkOkay"].Value);
if (isSelected)
{
string colValue = row.Cells["EnrollName"].Value.ToString();
EnrollNameList.Add(colValue);
Console.WriteLine("Selected Values " + colValue);
}
}
int v = 0;
while (v < EnrollNameList.Count)
{
//message box show whole EnrollName
MessageBox.Show("Name: " + EnrollNameList[v]);
foreach (var chari in EnrollNameList[v])
{
//get each char in EnrollName
}
v++;
}
strings can be indexed like arrays. Treating a string like an array (and adding an indexer in square brackets) returns the char at that position in the string.. "John"[0] is 'J'. Your value is a single string, not an array of strings.
With this:
value += row.Cells["EnrollName"].Value.ToString();
You're making a string value a longer and longer string. If your grid has 3 rows containing "mark", "luke" and "john", your value ends up as "marklukejohn"
If you then loop over it, you messagebox it out a char at a time
I suspect you want to retain the strings as whole strings (3 of them) in an array (or list).. in which case:
var names = new List<string>();
foreach ....
names.Add(row.Cells["EnrollName"].Value.ToString())
Then you can later loop over the list and pull the names out as complete strings
while (v < names.Count)
{
MessageBox.Show("Name: " + names[v] + "Slot: " + u);
Your code is full of syntax errors and won't compile. Do try to get code working before you post it unless the question is about a compiler error

C# Add a blank value in between string in of CSV file

I have this on a string that is generated from a list how can I add a blank value in between the string.
using (var file = File.CreateText()
{
foreach (var permutation in result)
{
file.WriteLine(string.Join(",", permutation));
//i++;
}
}
Here is the result:
string result = A,B,C,D,E,F,G,H,I,J
How can I add a blank value ", ," in the result at a specific index
Example: A,B,C,D,E,F, ,G,H,I,J
Note: result is a permutation and length is not consistent
Result is a IEnumerable can it be split?
You can split your string with the comma as the separator, go through your characters and add them to a list. Add an extra empty string at your desired index and join the data back together. This way you don't have to deal with deciding if you need to add a commar or not when concatenating the strings.
var index = 6;
var data = "A,B,C,D,E,F,G,H,I,J";
var chars = data.Split(new [] { ',' });
List<string> resultData = new List<string>();
var i = 0;
foreach (var c in chars) {
if (i == index) {
resultData.Add(" ");
}
i++;
resultData.Add(c);
}
var result = string.Join(",", resultData.ToArray();
You can use the following basic algorithm to follow your questions code logic:
using (var file = File.CreateText())
{
int i = -1;// Loop counter
int termReplacementIndex = 3;// Input or constant to find letter to replace
foreach (var permutation in result)
{
i++;
if (i == ((termReplacementIndex * 2) - 2))// Only stops on letters not commas
{
file.WriteLine(string.Join(",", " ,"));// Adding of blank " "
}
file.WriteLine(string.Join(",", permutation));// Adding of letter
}
}
If permutation is a list you can just insert a null value at the required index:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var list = new List<string>();
list.Add("test 1");
list.Add("test 2");
list.Add("test 3");
list.Insert(2, null);
var str = string.Join(",", list);
Console.WriteLine(str); // test 1,test 2,,test 3
}
}
Modify the Collection before joining it so you wont have to split it and iterate it again.
As the side of permutation vary you could be trying to insert at index X when X is larger greater permutation.Count() instead of an ArgumentOutOfRangeException I decide to add the element at the end. But you will have to define that.
public string CsvProjection(List<string> inputs, int needleIndex, string needleValue)
{
if (needleIndex < 0)
{
throw new ArgumentOutOfRangeException("needleIndex must be positive.");
}
if (needleIndex > inputs.Count())
{//Either throw an exception because out of bound or add to the end
inputs.Add(needleValue);
}
inputs.Insert(needleIndex, needleValue);
return string.Join(",", inputs);
}
Usage simply add the value and the index variable:
var needleIndex= 2;
var needleValue = "My New Value";
using (var file = File.CreateText()
{
foreach (var permutation in result)
{
file.WriteLine(CsvProjection(permutation, needleIndex, needleValue));
}
}

Splitting a line of text that has key value pairs where value can be empty

I need to split a line of text
The general syntax for a delivery instruction is |||name|value||name|value||…..|||
Each delivery instruction starts and ends with 3 pipe characters - |||
A delivery instruction is a set of name/value pairs separated by a single pipe eg name|value
Each name value pair is separated by 2 pipe characters ||
Names and Values may not contain the pipe character
The value of any pair may be a blank string.
I need a regex that will help me resolve the above problem.
My latest attempt with my limited Regex skills:
string SampleData = "|||env|af245g||mail_idx|39||gen_date|2016/01/03 11:40:06||docm_name|Client Statement (01.03.2015−31.03.2015)||docm_cat_name|Client Statement||docm_type_id|9100||docm_type_name|Client Statement||addr_type_id|1||addr_type_name|Postal address||addr_street_nr|||addr_street_name|Robinson Road||addr_po_box|||addr_po_box_type|||addr_postcode|903334||addr_city|Singapore||addr_state|||addr_country_id|29955||addr_country_name|Singapore||obj_nr|10000023||bp_custr_type|Customer||access_portal|Y||access_library|Y||avsr_team_id|13056||pri_avsr_id|||pri_avsr_name|||ctact_phone|||dlv_type_id|5001||dlv_type_name|Channel to standard mail||ao_id|14387||ao_name|Corp Limited||ao_title|||ao_mob_nr|||ao_email_addr||||??";
string[] Split = Regex.Matches(SampleData, "(\|\|\|(?:\w+\|\w*\|\|)*\|)").Cast<Match>().Select(m => m.Value).ToArray();
The expected output should be as follows(based on the sample data string provided):
env|af245g
mail_idx|39
gen_date|2016/01/03 11:40:06
docm_name|Client Statement (01.03.2015−31.03.2015)
docm_cat_name|Client Statement
docm_type_id|9100
docm_type_name|Client Statement
addr_type_id|1
addr_type_name|Postal address
addr_street_nr|
addr_street_name|Robinson Road
addr_po_box|
addr_po_box_type|
addr_postcode|903334
addr_city|Singapore
addr_state|
addr_country_id|29955
addr_country_name|Singapore
obj_nr|10000023
bp_custr_type|Customer
access_portal|Y
access_library|Y
avsr_team_id|13056
pri_avsr_id|
pri_avsr_name|
ctact_phone|
dlv_type_id|5001
dlv_type_name|Channel to standard mail
ao_id|14387
ao_name|Corp Limited
ao_title|
ao_mob_nr|
ao_email_addr|
You can also do it without using Regex. Its just simple splitting.
string nameValues = "|||zeeshan|1||ali|2||ahsan|3|||";
string sub = nameValues.Substring(3, nameValues.Length - 6);
Dictionary<string, string> dic = new Dictionary<string, string>();
string[] subsub = sub.Split(new string[] {"||"}, StringSplitOptions.None);
foreach (string item in subsub)
{
string[] nameVal = item.Split('|');
dic.Add(nameVal[0], nameVal[1]);
}
foreach (var item in dic)
{
// Retrieve key and value here i.e:
// item.Key
// item.Value
}
Hope this helps.
I think you're making this more difficult than it needs to be. This regex yields the desired result:
#"[^|]+\|([^|]*)"
Assuming you're dealing with a single, well-formed delivery instruction, there's no need to match the starting and ending triple-pipes. You don't need to worry about the double-pipe separators either, because the "name" part of the "name|value" pair is always present. Just look for the first thing that looks like a name with a pipe following it, and everything up to the next pipe character is the value.
(?<=\|\|\|).*?(?=\|\|\|)
You can use this to get all the key value pairs between |||.See demo.
https://regex101.com/r/fM9lY3/59
string strRegex = #"(?<=\|\|\|).*?(?=\|\|\|)";
Regex myRegex = new Regex(strRegex, RegexOptions.Multiline);
string strTargetString = #"|||env|af245g||mail_idx|39||gen_date|2016/01/03 11:40:06||docm_name|Client Statement (01.03.2015−31.03.2015)||docm_cat_name|Client Statement||docm_type_id|9100||docm_type_name|Client Statement||addr_type_id|1||addr_type_name|Postal address||addr_street_nr|||addr_street_name|Robinson Road||addr_po_box|||addr_po_box_type|||addr_postcode|903334||addr_city|Singapore||addr_state|||addr_country_id|29955||addr_country_name|Singapore||obj_nr|10000023||bp_custr_type|Customer||access_portal|Y||access_library|Y||avsr_team_id|13056||pri_avsr_id|||pri_avsr_name|||ctact_phone|||dlv_type_id|5001||dlv_type_name|Channel to standard mail||ao_id|14387||ao_name|Corp Limited||ao_title|||ao_mob_nr|||ao_email_addr||||??";
foreach (Match myMatch in myRegex.Matches(strTargetString))
{
if (myMatch.Success)
{
// Add your code here
}
}
Here's a variation of #Syed Muhammad Zeeshan code that runs faster:
string nameValues = "|||zeeshan|1||ali|2||ahsan|3|||";
string[] nameArray = nameValues.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, string> dic = new Dictionary<string, string>();
int i = 0;
foreach (string item in nameArray)
{
if (i < nameArray.Length - 1)
dic.Add(nameArray[i], nameArray[i + 1]);
i = i + 2;
}
Interesting, I will like to try:
class Program
{
static void Main(string[] args)
{
string nameValueList = "|||zeeshan|1||ali|2||ahsan|3|||";
while (nameValueList != "|||")
{
nameValueList = nameValueList.TrimStart('|');
string nameValue = GetNameValue(ref nameValueList);
Console.WriteLine(nameValue);
}
Console.ReadLine();
}
private static string GetNameValue(ref string nameValues)
{
string retVal = string.Empty;
while(nameValues[0] != '|') // for name
{
retVal += nameValues[0];
nameValues = nameValues.Remove(0, 1);
}
retVal += nameValues[0];
nameValues = nameValues.Remove(0, 1);
while (nameValues[0] != '|') // for value
{
retVal += nameValues[0];
nameValues = nameValues.Remove(0, 1);
}
return retVal;
}
}
https://dotnetfiddle.net/WRbsRu

SubString editing

I've tried a few different methods and none of them work correctly so I'm just looking for someone to straight out show me how to do it . I want my application to read in a file based on an OpenFileDialog.
When the file is read in I want to go through it and and run this function which uses Linq to insert the data into my DB.
objSqlCommands.sqlCommandInsertorUpdate
However I want to go through the string , counting the number of ","'s found . when the number reaches four I want to only take the characters encountered until the next "," and do this until the end of the file .. can someone show me how to do this ?
Based on the answers given here my code now looks like this
string fileText = File.ReadAllText(ofd.FileName).Replace(Environment.NewLine, ",");
int counter = 0;
int idx = 0;
List<string> foo = new List<string>();
foreach (char c in fileText.ToArray())
{
idx++;
if (c == ',')
{
counter++;
}
if (counter == 4)
{
string x = fileText.Substring(idx);
foo.Add(fileText.Substring(idx, x.IndexOf(',')));
counter = 0;
}
}
foreach (string s in foo)
{
objSqlCommands.sqlCommandInsertorUpdate("INSERT", s);//laClient[0]);
}
However I am getting an "length cannot be less than 0" error on the foo.add function call , any ideas ?
A Somewhat hacky example. You would pass this the entire text from your file as a single string.
string str = "1,2,3,4,i am some text,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20";
int counter = 0;
int idx = 0;
List<string> foo = new List<string>();
foreach (char c in str.ToArray())
{
idx++;
if (c == ',')
{
counter++;
}
if (counter == 4)
{
string x = str.Substring(idx);
foo.Add(str.Substring(idx, x.IndexOf(',')));
counter = 0;
}
}
foreach(string s in foo)
{
Console.WriteLine(s);
}
Console.Read();
Prints:
i am some text
9
13
17
As Raidri indicates in his answer, String.Split is definitely your friend. To catch every fifth word, you could try something like this (not tested):
string fileText = File.ReadAllText(OpenDialog.FileName).Replace(Environment.NewLine, ",");
string words[] = fileText.Split(',');
List<string> everFifthWord = new List<string>();
for (int i = 4; i <= words.Length - 1, i + 5)
{
everyFifthWord.Add(words[i]);
}
The above code reads the selected file from the OpenFileDialog, then replaces every newline with a ",". Then it splits the string on ",", and starting with the fifth word takes every fifth word in the string and adds it to the list.
File.ReadAllText reads a text file to a string and Split turns that string into an array seperated at the commas:
File.ReadAllText(OpenDialog.FileName).Split(',')[4]
If you have more than one line use:
File.ReadAllLines(OpenDialog.FileName).Select(l => l.Split(',')[4])
This gives an IEnumerable<string> where each string contains the wanted part from one line of the file
It's not clear to me if you're after every fifth piece of text between the commas or if there are multiple lines and you want only the fifth piece of text on each line. So I've done both.
Every fifth piece of text:
var text = "1,2,3,4,i am some text,6,7,8,9"
+ ",10,11,12,13,14,15,16,17,18,19,20";
var everyFifth =
text
.Split(',')
.Where((x, n) => n % 5 == 4);
Only the fifth piece of text on each line:
var lines = new []
{
"1,2,3,4,i am some text,6,7",
"8,9,10,11,12,13,14,15",
"16,17,18,19,20",
};
var fifthOnEachLine =
lines
.Select(x => x.Split(',')[4]);

Need some help on a Regex match / replace pattern

My ultimate goal here is to turn the following string into JSON, but I would settle for something that gets me one step closer by combining the fieldname with each of the values.
Sample Data:
Field1:abc;def;Field2:asd;fgh;
Using Regex.Replace(), I need it to at least look like this:
Field1:abc,Field1:def,Field2:asd,Field2:fgh
Ultimately, this result would be awesome if it can be done via Regex in a single call.
{"Field1":"abc","Field2":"asd"},{"Field1":"def","Field2":"fgh"}
I've tried many different variations of this pattern, but can't seem to get it right:
(?:(\w+):)*?(?:([^:;]+);)
Only one other example I could find that is doing something similar, but just enough differences that I can't quite put my finger on it.
Regex to repeat a capture across a CDL?
EDIT:
Here's my solution. I'm not going to post it as a "Solution" because I want to give credit to one that was posted by others. In the end, I took a piece from each of the posted solutions and came up with this one. Thanks to everyone who posted. I gave credit to the solution that compiled, executed fastest and had the most accurate results.
string hbi = "Field1:aaa;bbb;ccc;ddd;Field2:111;222;333;444;";
Regex re = new Regex(#"(\w+):(?:([^:;]+);)+");
MatchCollection matches = re.Matches(hbi);
SortedDictionary<string, string> dict = new SortedDictionary<string, string>();
for (int x = 0; x < matches.Count; x++)
{
Match match = matches[x];
string property = match.Groups[1].Value;
for (int i = 0; i < match.Groups[2].Captures.Count; i++)
{
string key = i.ToString() + x.ToString();
dict.Add(key, string.Format("\"{0}\":\"{1}\"", property, match.Groups[2].Captures[i].Value));
}
}
Console.WriteLine(string.Join(",", dict.Values));
Now you have two problems
I don't think regular expressions will be the best way to handle this. You should probably start by splitting on semicolons, then loop through the results looking for a value that starts with "Field1:" or "Field2:" and collect the results into a Dictionary.
Treat this as pseudo code because I have not compiled or tested it:
string[] data = input.Split(';');
dictionary<string, string> map = new dictionary<string, string>();
string currentKey = null;
foreach (string value in data)
{
// This part should change depending on how the fields are defined.
// If it's a fixed set you could have an array of fields to search,
// or you might need to use a regular expression.
if (value.IndexOf("Field1:") == 0 || value.IndexOf("Field2:"))
{
string currentKey = value.Substring(0, value.IndexOf(":"));
value = value.Substring(currentKey.Length+1);
}
map[currentKey] = value;
}
// convert map to json
I had an idea that it should be possible to do this in a shorter and more clear way. It ended up not being all that much shorter and you can question if it's more clear. At least it's another way to solve the problem.
var str = "Field1:abc;def;Field2:asd;fgh";
var rows = new List<Dictionary<string, string>>();
int index = 0;
string value;
string fieldname = "";
foreach (var s in str.Split(';'))
{
if (s.Contains(":"))
{
index = 0;
var tmp = s.Split(':');
fieldname = tmp[0];
value = tmp[1];
}
else
{
value = s;
index++;
}
if (rows.Count < (index + 1))
rows.Insert(index, new Dictionary<string, string>());
rows[index][fieldname] = value;
}
var arr = rows.Select(dict =>
String.Join("," , dict.Select(kv =>
String.Format("\"{0}\":\"{1}\"", kv.Key, kv.Value))))
.Select(r => "{" + r + "}");
var json = String.Join(",", arr );
Debug.WriteLine(json);
Outputs:
{"Field1":"abc","Field2":"asd"},{"Field1":"def","Field2":"fgh"}
I would go with RegEx as the simplest and most straightforward way to parse the strings, but I'm sorry, pal, I couldn't come up with a clever-enough replacement string to do this in one shot.
I hacked it out for fun through, and the monstrosity below accomplishes what you need, albeit hideously. :-/
Regex r = new Regex(#"(?<FieldName>\w+:)*(?:(?<Value>(?:[^:;]+);)+)");
var matches = r.Matches("Field1:abc;def;Field2:asd;fgh;moo;"); // Modified to test "uneven" data as well.
var tuples = new[] { new { FieldName = "", Value = "", Index = 0 } }.ToList(); tuples.Clear();
foreach (Match match in matches)
{
var matchGroups = match.Groups;
var fieldName = matchGroups[1].Captures[0].Value;
int index = 0;
foreach (Capture cap in matchGroups[2].Captures)
{
var tuple = new { FieldName = fieldName, Value = cap.Value, Index = index };
tuples.Add(tuple);
index++;
}
}
var maxIndex = tuples.Max(tup => tup.Index);
var jsonItemList = new List<string>();
for (int a = 0; a < maxIndex+1; a++)
{
var jsonBuilder = new StringBuilder();
jsonBuilder.Append("{");
foreach (var tuple in tuples.Where(tup => tup.Index == a))
{
jsonBuilder.Append(string.Format("\"{0}\":\"{1}\",", tuple.FieldName, tuple.Value));
}
jsonBuilder.Remove(jsonBuilder.Length - 1, 1); // trim last comma.
jsonBuilder.Append("}");
jsonItemList.Add(jsonBuilder.ToString());
}
foreach (var item in jsonItemList)
{
// Write your items to your document stream.
}

Categories

Resources