"Contains" method doesn't seem to working the way it should - c#

I'm trying to see if when a user enters some text it searches the array for any matches, and whatever doesn't match gets removed from the array;
string search = textBox1.Text;
for (int i = 0; i < staffUsers.Count; i++)
{
if (!(staffUsers[i].staff_name.Contains(search)))
{
staffUsers.Remove(staffUsers[i]);
}
}
I have some rubbish names in my array 'Rob Dob','Joe Bloggs', 'h h', 'ghg hgh', and if the search variable ended up being 'R', Joe Bloggs would get removed but 'h h' and 'ghg hgh' stay there, but there is no R involved there at all? any reason why>?!

You have to iterate backwards in order to remove from an array. Every time you remove an item, your array gets smaller. By going backwards, that fact does not matter.
string search = textBox1.Text;
for (int i = staffUsers.Count - 1; i >= 0 ; i--)
{
if (!(staffUsers[i].staff_name.Contains(search)))
{
staffUsers.Remove(staffUsers[i]);
}
}

The problem with your code is that you are removing items as you iterate over it. You remove an item, but keep iterating, even though the size of the array changes when you remove an item.
You need to reset your i value after you remove something. Alternatively, you need to use a built in to do the heavy lifting:
staffUsers.RemoveAll(i => !(i.staff_name.Contains(search)));
Uses a tiny LINQ expression to do the work. Remove all items where that predicate matches. i represents an item to apply the expression to. If that expression evaluates to true, away it goes.

Long story short, whenever you remove an item at index [i], you skip the item at index [i+1]. For example, if your array looks like:
{'Joe Bloggs', 'Rob Dobb', 'h h', 'gafddf'}; i=0
remove Joe Bloggs, which is at position 0.
{Rob Dobb', 'h h', 'gafddf'}; i=1
remove 'h h', which is at position 1
{Rob Dobb', 'gafddf'}; i=2
i is not less than yourArray.Count, so the loop stops. There is no position 2.
The quickest fix is to add i-- if you remove something from index [i]. In your case,
staffUsers.Remove(staffUsers[i]);
i--;
Hope this helps!

In each iteration of the loop, either remove an item or increment the counter, not both operations. Otherwise, you'll skip the next array element whenever you remove an array element:
string search = textBox1.Text;
for (int i = 0; i < staffUsers.Count;)
{
if (!(staffUsers[i].staff_name.Contains(search)))
{
staffUsers.Remove(staffUsers[i]);
}
else
{
i++;
}
}

The simplest way to solve the above problem is using LINQ.
Following code disentangle above problem.
string search = textBox1.Text;
staffUsers= (from user in staffUsers
where !user.Contains(search)
select user).ToArray<string>();
Note: I assumed staffUsers is array of string.

string search = textBox1.Text;
for (int i = 0; i < staffUsers.Count; i++)
{
if (!(staffUsers[i].staff_name.Contains(search)))
{
staffUsers.Remove(staffUsers[i]);
// reset the index one stepback
i--;
}
}

Related

Trying to delete an entry from a structure array in C#. Getting conflicting information?

I have been researching this topic and got conflicting answers. Any help is appreciated.
For an assignment, I am instructed to create a structure of arrays. I am trying to delete an entry in one case, and change in another. This is supposed to be by one of the fields and not by index number.
var countOfEmployees = 0;
var employees = new EmployeeData[100];
Console.Write("Please enter employee you want to delete:");
string deleteEmployee = Console.ReadLine();
bool deleted = false;
for (int x = 0; x < countOfemployees; x++)
{
if (items[x].ItemNumber == deleteItemNumber)
{
deleted = true;
}
if (true)
{
//code goes here
}
Any help is appreciated!
In an array, you might be able to delete the value from the place holder, but you will not be able to remove the actual item without some footwork.
Basically, what you can do is: Find the value you've searched for, and replace it with a null and treat it orrespondingly in every other function.
Option 2 would be to remove the item and then use a function that would "shift" all the values with a higher index upwards.
Option 3 is to use the advanced functions C#/.NET has to offer with collections, create a List, remove the item and cast back to an array.
var employees = new EmployeeData[100];
var list = employees.ToList();
int index=-1;
//search through in a loop (won't write it here)...
index = x; //get the index in your list then break the loop
break; //end the loop
list.RemoveAt(index); //delete the spot outside the loop
employees=list.ToArray();
Of course there's checks needed if the search didn't find anything, but i think you can manage to implement that without my help.
And this is of course me assuming that there's only ONE entry with that kind of value in the array.
If it's not, you're gonna have to loop through and erase them until the search doesn't find anything anymore.

Loop to Check if Index Has Repeated in C#

I would like to create a for loop to check if an index value has repeated, and if it has to remove it from the original and display an updated list with no repeated index values.
I have and Array (called Original) with multiple values being repeated, and then I created a Temporary Array (called TempArray) with the same exact values.
I want to check the Original and TempArray values against each other to see if there are duplicates.
I want my code to be similar to a previous one I did where I deleted an index from the middle of my array, as follows
for (int i = 0; i < Original.Length; i++)
{
TempArray[i] = Original[i];
}
Original = new int[Original.Length - 1];
//Set index to delete
int DeleteIndex = 3;
//modify size of Orignial array and copy in array without deleted element index
for (int i = 0; i < TempArray.Length; i++)
{
if (i < DeleteIndex)
{
Original[i] = TempArray[i];
}
else if (i > DeleteIndex)
{
Original[i - 1] = TempArray[i];
}
}
P.S. Original[] is an array from a text file. Sorry if my explanation is hard to understand as I am new to computer programming.
Also is there any way to do this code without LINQ, I have to create using arrays only as its all thats been taught at school?
It took some time to understand what you want :)
to check if an index value has repeated, and if it has to remove it from the original and display an updated list with no repeated index values
It is shortly called distinct values. There is a LINQ method .Distinct():
Original = Original.Distinct().ToArray();
It will remove all repeated values.
where I deleted an index from the middle of my array
You can do this easier by converting to List, applying RemoveAt and back:
var list = new List<int>(Original);
list.RemoveAt(DeleteIndex);
Original = list.ToArray();
P.S. Assuming that you say "index" about the values in your array, it is pretty confusing. Array does not store indices - index is usually understood as a key of an array.
May be this will do the trick for you. I am assuming that you need to remove duplicate from your array
Original = Original.Distinct().ToArray();
Will Returns distinct elements from a sequence by using the default equality comparer to compare values.

Nested For loop multidimensional array search

Got a silly question im struggling with.
Im trying to step through a C# Multidimensional array using nested for loops, but i cant get the result i want and im thinking its just a stupid problem with my code.
string search = txtString.Text;
int iLoop;
int jloop;
int iResult = -1;
for (iLoop = 0; iLoop < sounds.GetLength(0) ; iLoop++)
{
for (jloop = 0; jloop < sounds.GetLength(1) ; jloop++)
{
string result;
result = sounds[iLoop,jloop];
if (result == search)
{
iResult = iloop;
}
}
}
if (iResult == -1)
{
MessageBox.Show("Result not found");
}
else
{
MessageBox.Show("Result found at position " + iResult);
}
}
It searches the array, and returns a positive result if the answer is found, but the result position is always "Result found at position 1".
What have i done wrong?
You are storing only one dimension (iResult). It can always be 1, but second dimension (jresult) can vary.
And just reminder for future projects in different languages. Try no to use if (result == search) for strings. Use Equal or Compare methods.
There are two indices to look up: jloop and iLoop , probably you will get various jloop values in the 2D array
Also check the name on the parameter you use, sometimes you call it iLoop, others iloop.
Be consistent! :)
I guess the answer is always in row 1, you just pring the i value, print also the j value jLoop.
Keep in mind that this code snippet will continue searching even after it has found a match. So in fact what you are finding is the last position of the matched text.
As an aside, perhaps instead of reporting only the matching iLoop, you could report both the matching iLoop and jLoop. Or, you can report a single index as iLoop * sounds.GetLength(0) + jLoop

Row Index provided is out of range, even after check

My current code:
Remove()
{
for (int i = 0; i < ConGridView.RowCount; i++)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
ConGridView.Rows.RemoveAt(i);
break;
}
}
}
So what I am trying to call the remove function every time a client disconnect. the function will remove the connection address from the datagridview. It works well when clients are disconnection one by one. However, if 100 connections gets dropped and it tries to remove 100 connections in less than a second, than it errors out saying "Row Index provided is out of range". How should I check for that ?
So far I've tried:
Try, catch.
if (ConGridView.Rows[i] != null), if (i < ConGridView.RowCount)
None of it seem to work so far. I've also got results using (i < ConGridView.RowCount) where i is 26 while RowCount is 24, but the remove at function still activates..
Any idea on this ?
You can't do this. Your code loops through all the rows in ConGridView, but it deletes them as you do. Therefore, at some point you will try to access an item you have deleted, which will cause the error you described.
Probably the best approach it to iterate through the rows in reverse order. This way, deleting a row at the end won't affect when you access rows at the start.
The problem is you initialise your for loop with the current count of rows and then start removing those same rows from the datagridview. At some point your for loop will try to remove a row at an index that is greater than the number of rows left.
Try this instead:
for (int i = ConGridView.RowCount - 1; i >= 0; i--)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
ConGridView.Rows.RemoveAt(i);
break;
}
}
why dont you get the total count to a separate variable and then iterate
Remove()
{
int totalConnections = ConGridView.RowCount;
for (int i = 0; i < totalConnections ; i++)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
ConGridView.Rows.RemoveAt(i);
break;
}
}
}
This issue is becuase you are modifying the collection your are iterating over. It will be better if you use a temporary array and two loops to remove your entries.
Remove()
// You can use an array/list or whatever you want below.
Collection<DataGridViewRow> rowsToDelete = new Collection<DataGridViewRow>();
for (int i = 0; i < ConGridView.RowCount; i++)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
rowsToDelete.Add(ConGridView.Rows[i]);
break;
}
}
// now remove the marked entries.
foreach(DataGridViewRow deletedRow in rowsToDelete)
{
ConGridView.Rows.Remove(deletedRow);
}
When you remove an item from an array, it is reconstructed; shifting the remaining elements up by one to remove the gap of the index you have removed.
1. guybrush threepwood
2. murray
3. elaine
4. Jimmy Gibbs Jr.
If you remove 2. item in here; it becomes this:
1. guybrush threepwood
2. elaine
3. Jimmy Gibbs Jr.
When you are iterating, imagine:
for (int i = 0; i < myArray.Count; i++)
{
if (i == 2) myArray.RemoveAt(i);
}
While running this, when i = 3, the element at 3 has changed, you expect it to be 'elaine' but it is 'Jimmy Gibbs Jr.'. One way to fix this is decrease i by one if we delete it, making sure that i refers to correct value.
for (int i = 0; i < myArray.Count; i++)
{
if (i == 2)
{
myArray.RemoveAt(i);
i--;
}
}
I would go for LINQ in this case, though, everything is easier with that.
myArray.RemoveAll(x => x == "murray");
I've tried all the suggestions posted by everyone here, however, the error was still there.
I've solved the problem using a different way... I've switched to TreeNodeView since that's what I was going to use ultimately. Now I can remove as many connection as i want with:
For each(TreeNode TN in ConTreeView)
{
ConTreeView.Nodes.Remove(TN);
}

Clear all array list data

Why doesn't the code below clear all array list data?
Console.WriteLine("Before cleaning:" + Convert.ToString(ID.Count));
//ID.Count = 20
for (int i = 0; i < ID.Count; i++)
{
ID.RemoveAt(i);
}
Console.WriteLine("After cleaning:" + Convert.ToString(ID.Count));
//ID.Count = 10
Why is 10 printed to the screen?
Maybe there is another special function, which deletes everything?
You're only actually calling RemoveAt 10 times. When i reaches 10, ID.Count will be 10 as well. You could fix this by doing:
int count = ID.Count;
for (int i = 0; i < originalCount; i++)
{
ID.RemoveAt(0);
}
This is an O(n2) operation though, as removing an entry from the start of the list involves copying everything else.
More efficiently (O(n)):
int count = ID.Count;
for (int i = 0; i < originalCount; i++)
{
ID.RemoveAt(ID.Count - 1);
}
or equivalent but simpler:
while (ID.Count > 0)
{
ID.RemoveAt(ID.Count - 1);
}
But using ID.Clear() is probably more efficient than all of these, even though it is also O(n).
`Array.Clear()`
removes all items in the array.
`Array.RemoveAt(i)`
removes the element of ith index in the array.
ArrayList.Clear Method
Removes all elements from the ArrayList.
for more detail : http://msdn.microsoft.com/en-us/library/system.collections.arraylist.clear.aspx
After removing 10 items, ID.Count() == 10 and i == 10 so the loop stops.
Use ID.Clear() to remove all items in the array list.
Use the clear() Method
or
change ID.RemoveAt(i); to ID.RemoveAt(0);
Whenever an element is removed from the collection, its index also changes. Hence when you say ID.RemoveAt(0); the element at index 1 now will be moved to index 0. So again you've to remove the same element (like dequeuing). until you reach the last element. However if you want to remove all the elements at once you can better use the Clear() method.
Your code does:
ID.RemoveAt(0);
...
ID.RemoveAt(9);
ID.RemoveAt(10); \\ at this point you have already removed 10
\\ items so there is nothing left on 10- 19, but you are left with
\\ the 'first' 10 elements
...
ID.RemoveAt(19);
Generally speaking your method removes every second element from the list..
Use ArrayList.Clear instead as other have mentioned.

Categories

Resources