How do i compare string and substrings out of DataTables? - c#

I have a DataTable with 1 column and a List of DataTables with 2 columns each.
I want to compare the Value of the DataTable with the first 6 digits of the Value of each DataTable in the List row by row.
This is my Code:
for(int fs = 0; fs < dataTable.Rows.Count; fs++)
{
for(int fs2 = 0; fs < dataTableList.Count; fs2++)
{
for(int fs3 = 0; fs3 < dataTableList[fs2].Rows.Count; fs3++)
{
if(dataTable.Rows[fs]["columnName"].ToString().Equals(dataTableList[fs2].Rows[fs3]["otherColumnName"].ToString().Substring(0,6)))
{
//do sth.
}
}
}
}
When the program reaches if(dataTable.Rows[fs]["columnName"].ToString().Equals(dataTableList[fs2].Rows[fs3]["otherColumnName"].ToString().Substring(0,6))) it stops and i get an System.ArgumentOutOfRangeException error.
Does anybody know what I am doing wrong? When I MessageBox the substring it is working.

So, first of all, I suggest refactoring this monstrosity to foreach loops.
foreach(var row in dataTable.Rows)
{
foreach(var otherDataTable in dataTableList)
{
foreach(var otherRow in otherDataTable.Rows)
{
/* ... */
}
}
}
And then checking if the string you're trying to get a substring of actually has length of 6 or more.
const int compareLength = 6;
const string columnName = "columnName";
const string otherColumnName = "otherColumnName";
foreach(var row in dataTable.Rows)
{
foreach(var otherDataTable in dataTableList)
{
foreach(var otherRow in otherDataTable.Rows)
{
var value = row[columnName].ToString();
var otherValue = otherRow[otherColumnName].ToString();
if(otherValue.Length >= compareLength &&
value == otherValue.Substring(0, compareLength))
{
/* Do something. */
}
}
}
}
My bet is that Substring call when the compared value was shorter than 6 was the problem. See if this helps.

Related

Get Occurrences of Letters in A String

I am trying to count occurrences of letters in a string and almost got the result using the below code snippet:
public static void GetNoofLetters()
{
string str = "AAAAABBCCCDDDD";
int count = 1;
char[] charVal = str.ToCharArray();
List<string> charCnt = new List<string>();
string concat = "";
//Getting each letters using foreach loop
foreach (var ch in charVal)
{
int index = charCnt.FindIndex(c => c.Contains(ch.ToString())); //Checks if there's any existing letter in the list
if(index >= 0) //If letter exists, then count and replace the last value
{
count++;
charCnt[charCnt.Count - 1] = count.ToString() + ch.ToString();
}
else
{
charCnt.Add(ch.ToString()); //If no matching letter exists, then add it to the list initially
count = 1;
}
}
foreach (var item in charCnt)
{
concat += item;
}
Console.WriteLine(concat.Trim());
}
The code works for the given input sample and returns output as: 5A2B3C4D. Simple is that.
But say I've the following input: Second input sample
string str = "AAAAABBCCCDDDDAA";
Expected output:
5A2B3C4D2A
With the above code that I've returns the output as follows:
5A2B3C6A
The above actually occurred for the below code snippet:
if(index >= 0) //If letter found, then count and replace the last value
{
count++;
charCnt[charCnt.Count - 1] = count.ToString() + ch.ToString();
}
Is there any better idea that I can resolve to get the expected output for the second input sample? I can understand, am close enough and may be missing something that's simple enough.
Code sample: Count Occurrences of Letters
Why don't we just loop over value and count? We can have two possibilities:
When character c doesn't equal to current (we have the different character) we should write down the previous sequence and start a new one
Otherwise, add 1 to count
Code:
private static string Compress(string value) {
if (string.IsNullOrEmpty(value))
return value;
char current = '\0';
int count = 0;
StringBuilder result = new StringBuilder(2 * value.Length);
foreach (char c in value) {
if (count != 0 && c != current) {
result.Append(count);
result.Append(current);
count = 0;
}
current = c;
count += 1;
}
result.Append(count);
result.Append(current);
return result.ToString();
}
Please, fiddle yourself
Well, I ended with the following code sample:
public static void Main()
{
string str = "AAAAABBCCCDDDDAABBBBAABB";
int count = 1;
char[] charVal = str.ToCharArray();
List<string> charCnt = new List<string>();
charCnt.Add("");
string concat = "";
//Getting each letters using foreach loop
foreach (var ch in charVal)
{
var lastItem = charCnt.LastOrDefault();
if (lastItem.EndsWith((ch.ToString()))) //If letter exists, then count and replace the last value
{
count++;
charCnt[charCnt.Count - 1] = count.ToString() + ch.ToString();
}
else
{
charCnt.Add(ch.ToString()); //If no matching letter exists, then add it to the list initially
count = 1;
}
}
foreach (var item in charCnt)
{
concat += item; //Concatenate items from the list
}
Console.WriteLine(concat.Trim());
}
Here's a woking sample: Get Occurrences of Letters in A String

for loop skip list elements

i have a problem with the code i showed below.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace problem2
{
class Program
{
static void Main(string[] args)
{
int[] nums = Console.ReadLine().Split().Select(int.Parse).ToArray();
List<int> lst = nums.OfType<int>().ToList();
while (true)
{
string des = Console.ReadLine();
var output = Regex.Replace(des.Split(" ")[0], #"[^0-9a-zA-Z\ ]+", "");
if (output == "Add")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
lst.Add(value);
}
else if(output == "Remove")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
lst.Remove(value);
}else if(output == "Replace")
{
String result1 = System.Text.RegularExpressions.Regex.Match(des, #"\d+").Value;
var lastno = des.Split().Last();
List<int> lst2 = lst;
for (int i = 0; i < lst2.Count; i++)
{
if(lst[i] == int.Parse(result1))
{
lst[i] = int.Parse(lastno);
break;
}
}
lst = lst2;
}
else if(output == "Collapse")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
}
else
{
continue;
}
}
}else if (output == "Mort")
{
PrintValues(lst);
break;
}
}
}
public static void PrintValues(IEnumerable myList)
{
foreach (Object obj in myList)
Console.Write("{0} ", obj);
Console.WriteLine();
}
}
}
more precisely with this part of the code:
else if(output == "Collapse")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
}
else
{
continue;
}
}
I tried with all sorts of options but the loop misses elements. as an example
entrance:
1 2 -1 0 -3 9 8 7 2
Collapse 8
Mort
output:
9 8
but the program gives me this output:
2 0 9 8 2
I tried to see what the problem is through the debugger and there I found that the loop misses elements
It should be,
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
i--;
}
else
{
continue;
}
}
As #David784 mentioned at the comments. When you remove element the from the itterating collection. You miss 1 element everytime after you delete the i item.
To elaborate on #Berkay's comment: You're changing a list as you're looping through it. If i is 2 and you remove that element, then the element that used to be at index 3 now becomes 2, and so forth. His method of decrementing i will work. Another way would be to use a linq .Where statement instead:
var newList = lst.Where(e=> e>=value).ToList();
You are modifying the collection you are iterating through. This moves elements to other indexes and invalidates the i you determine for following elements in the for header. Better loop backwards
for (int i = lst.Count - 1; i >= 0; i--) {
// Now you can safely remove (or add) elements without affecting
// the index of non yet processed elements.
}
You are still modifying the index of elements ahead, but you are moving backwards, now.
In Visual Studio, you can use the forr code snippet to create a reverse for-loop. Type
forr <tab> <tab>.
(and of course there is the for code snippet for a normal for loop. It will increment the index with i++ instead of i += 1.)
Also, if the list is very long and you are removing many elements, it is worth to think about performance. This approach could move around a great number of elements. Copying the elements you want to keep to a new list (initialized with an appropriate initial capacity), will be more performing in this case.

find the first element of an array that is not consecutive using web forms

E.g. If we have an array [1,2,3,4,6,7,8] then 1 then 2 then 3 then 4 are all consecutive but 6 is not, so that's the first non-consecutive number.
If the whole array is consecutive then return null .
The array will always have at least 2 elements 1 and all elements will be numbers. The numbers will also all be unique and in ascending order. The numbers could be positive or negative and the first non-consecutive could be either too. please help me finish this code i am new in programming. My code:
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace _2katas
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var input = this.txtInput.Text;
var numarray = input.Split(',');
int firstValue = Convert.ToInt32(numarray[0]);
for (var i = 0; i < numarray.Length; i++)
{
if (Convert.ToInt32(numarray[i]) - i != firstValue)
{
lblPrint.Text = "";
}
else
{
lblPrint.Text = "";
}
if (this.rdbConsecutive.Checked == true)
{
lblKataRunning.Text = "Consecutive";
}
else if (this.rdbStripCleaning.Checked == true)
{
lblKataRunning.Text = "Strip Cleaning";
}
}
}
}
}
Let's extract a method:
Find the first element of an array that is not consecutive ...
If the whole array is consecutive then return null
We can implement it like this:
private static string FirstInconsecutive(string data) {
var array = data.Split(',');
if (array.Length <= 0)
return null; //TODO: what shall we return on empty array?
if (!int.TryParse(array[0], out int delta))
return array[0];
for (int i = 1; i < array.Length; ++i)
if (!int.TryParse(array[i], out int value) || value - i != delta)
return array[i];
return null;
}
Usage:
string result = FirstInconsecutive(txtInput.Text);
Please note int.TryParse which helps to return the right answer "ABC" on an input like "1, 2, 3, ABC, 4, 6, 7, 8" (user input txtInput.Text can contain any string)
A linq solution just for the fun of it:
static int? FindFirstNonConsecutive(IEnumerable<int> arr)
{
var nonConsecutiveInfo =
arr.Select((i, index) => new {Index = index, Delta = i - index})
.FirstOrDefault(t => t.Delta != arr.First());
return nonConsecutiveInfo?.Delta + nonConsecutiveInfo?.Index;
}
Note that this will only work finding non consecutive numbers in ascending order as per requirements.
Two numbers are not consecutive if the left ones + 1 <> the right one.
Check with something like this, note that you have to change your boundary checks:
for (var i = 0; i < numarray.Length - 1; i++)
{
if (Convert.ToInt32(numarray[i]) + 1 != Convert.ToInt32(numarray[i+1]))
Update your condition as below for loop and it will work. I would suggest you to have separate function so that it could be reusable if needed elsewhere in code.
Here start your loop from i = 1 and compare numarray[i-1] + 1 != numarray[i] values.
You can convert your sting[] to int[] with var numarray = input.Split(',').Select(x => Convert.ToInt32(x)).ToArray(); and use it with IsConsecutive(numarray) as per button1_Click code.
You can get first non-consecutive value with minor modification in return type and return statement as shown in GetFirstNonConsecutiveValue().
public bool IsConsecutive(int[] numarray)
{
for (int i = 1; i < numarray.Length; i++)
{
if (numarray[i-1] + 1 != numarray[i])
{
return false;
}
}
return true;
}
public int? GetFirstNonConsecutiveValue(int[] numarray)
{
for (int i = 1; i < numarray.Length; i++)
{
if (numarray[i-1] + 1 != numarray[i])
{
return numarray[i];
}
}
return null;
}
private void button1_Click(object sender, EventArgs e)
{
var input = this.txtInput.Text;
var numarray = input.Split(',').Select(x => Convert.ToInt32(x)).ToArray();
var nonConsecutiveValue = GetFirstNonConsecutiveValue(numarray);
if (nonConsecutiveValue != null)
{
// nonConsecutiveValue is first non consecutive value.
}
else
{
// sequence is consecutive.
}
}
One way to go.
string rawData = "1,2,3,4,6,7,8,9";
IEnumerable<int> data = rawData.Split(',').Select(v => Convert.ToInt32(v));
IEnumerable<int> all = Enumerable.Range(data.Min(), data.Max() - data.Min() + 1);
IEnumerable<int> diff = all.Except(data);
if (diff.Count() == 0)
{
return null;
}
return data.ElementAt(all.ToList().IndexOf(diff.First()))
NB Not thoroughly tested.
Just test diff for being empty to get the numbers are consecutive

How to replace list value with another value c#

I write some data into csv file from List but some list indexes has empty string but another indexes has value
in these cases the data compared with another list wrote in the same csv file
this is my csv file opened using excel sheet
in the third column there exist ID for the the second column cell so in the coming rows i want to detect the name of the ID based on previous rows
like in row 3 it's ID is 19 and name is I/O so in the 7th row the ID is 19 and want to fill the second cell now
info : the IDs is already known above and any next ID will be exist before
by the follwing code.
bool isInList = ms.IndexOf(ShapeMaster) != -1;
if (isInList)
{
savinglabelnamefortextbox = t.InnerText;
string replacement =
Regex.Replace(savinglabelnamefortextbox, #"\t|\n|,|\r", "");
xl.Add("");
dl.Add(replacement);
ms.Add(ShapeMaster);
}
and I use the following code to write to the csv file
using (StreamWriter sw = File.CreateText(csvfilename))
{
for (int i = 0; i < dl.Count; i++)
{
var line = String.Format("{0},{1},{2}", dl[i], xl[i],ms[i]);
sw.WriteLine(line);
}
}
Try this
for (int x = 0; x < ms.Count; x++)
{
if (xl[x] != "")
{
continue;
}
else if (xl[x] == "")
{
for (int y = 0; y<xl.Count; y++)
{
if (ms[y] == ms[x])
{
xl[x] = xl[y];
break;
}
}
continue;
}
}

Issue with .NET String.Split

I'm attempting to parse a text file containing data that is being used on a remote FTP server. The data is delimited by an equals sign (=) and I'm attempting to load each row in to two columns in a DataGridView. The code I have written works fine except for when an equals character is thrown into the second column's value. When this happens, regardless of specifying the maximum count as being 2. I'd prefer not to change the delimiter if possible.
Here is the code that is being problematic:
dataGrid_FileContents.Rows.Clear();
char delimiter = '=';
StreamReader fileReader = new StreamReader(fileLocation);
String fileData = fileReader.ReadToEnd();
String[] rows = fileData.Split("\n".ToCharArray());
for(int i = 0; i < rows.Length; i++)
{
String str = rows[i];
String[] items = str.Split(new char[] { delimiter }, 1, StringSplitOptions.RemoveEmptyEntries);
if (items.Length == 2)
{
dataGrid_FileContents.Rows.Add(items[0], items[1]);
}
}
fileReader.Close();
And an example of the file being loaded:
boats=123
cats=234-f
cars==1
It works as intended for the first two rows and then ignores the last row as it ends up creating a String[] with 1 element and two String[]s with zero elements.
Try the following. It will capture the value before and after the first '=', correctly parsing the cars==1 scenario.
String[] items = str.Split(new char[] { delimiter }, 2, stringSplitOptions.None);
A different solution, if you want everything after the first equals then you could approach this problem using string.IndexOf
for(int i = 0; i < rows.Length; i++)
{
String str = rows[i];
int pos = str.IndexOf(delimiter);
if (pos != -1)
{
string first = str.Substring(0, pos-1);
string second = str.Substring(pos + 1);
dataGrid_FileContents.Rows.Add(first, second);
}
}
Just read all items delimeted by '=' in row.
Then iterate over items, and check, that item not empty, than use this prepared data to write
here illustrated snippet
http://dotnetfiddle.net/msVho2
and your snippet can be transformed to something like bellow
dataGrid_FileContents.Rows.Clear();
char delimiter = '=';
using(StreamReader fileReader = new StreamReader(fileLocation))
{
string[] data = new string[2];
while(true)
{
string row = fileReader.ReadLine();
if(row == null)
break;
string[] items = row.Split(delimiter);
int data_index = 0;
foreach(string item in items)
{
if(data_index >= data.Length)
{
//TODO: log warning
break;
}
if(!string.IsNullOrWhiteSpace(item))
{
data[data_index++] = item;
}
}
if(data_index < data.Length)
{
//TODO: log error, only 1 item in row
continue;
}
dataGrid_FileContents.Rows.Add(data[0], data[1]);
}
}

Categories