Check if array cell has a value - c#

I'm grabbing a string of data where each element pair is delimited by the ';' character. So, I do a string split into an array to get each chunk of data.
Each chunk now consists of a label and value pair, which are delimited by a ':'. However, every so often the final element doesn't have a matching value. So for example:
food:cheese
name:dave
car:renault
somethingelse
I'm grabbing these pairs and splitting them into a second array which I then iterate via a foreach like so;
int a=0;
string[,] tmpInfo = new string[10, 2];
foreach(var info in details)
{
string[] tmp = info.Split(':');
if (tmp[1].ToString != null)
{
//do something
}
}
However, when I hit the odd scenario where the last element doesn't have the delimiter, I get an issue with "Index was outside the bounds of the array."
As you can see from my code I tried testing if the array cell was null. I've also tried testing for an empty string, but the issue persists.

Instead of your check if (tmp[1].ToString != null) , check for the Length of returned array like:
if(tmp.Length == 2) //if it should always be 2
In case of empty string or no delimiter in the string you would end up with 1 element in the array. Later when you try to access element at index 1, you will get exception since arrays are 0 based and tmp[1] means access second element of the returned array.

Related

How do I remove an empty element in an array? [duplicate]

This question already has answers here:
How to delete an element from an array in C#
(12 answers)
Closed 7 years ago.
I have an array of email address, but an empty string gets injected into the end of the array. How can I remove this element in the array?
for(int i = 0; i < allToAddresses.Length; i++)
{
if(allToAddresses[i] == " ") // find where empty element is
{ //Here i am trying to delete that empty element. does not work
allToAddresses[i].Split("".ToCharArray(),StringSplitOptions.RemoveEmptyEntries);
}
}
You could try to use Linq for this
allToAddresses = allToAddresses.Where(address=>!string.IsNullOrWhiteSpace(address))
.ToArray();
You have to include also this in your namespaces:
using System.Linq;
You filter your initial array using the Where method. In this method you pass a predicate that returns true if for the current address the method string.IsNullOrWhiteSpace returns false. Otherwise it returns false. Using this filter you discard the addresses that are null, empty, or consisted only of white-space characters.
test = test.Where(x => !string.IsNullOrWhitepace(x)).ToArray();
You cannot truly "remove" elements from an array, because array size is fixed*. You can, however, construct a new array that skips all empty elements:
allToAddresses = allToAddresses.Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
The above requires using System.Linq at the top of your file. It checks all entries in your array to see if they are null or consist entirely of white space (spaces, tabs, etc.) and produces a new array of strings, containing only non-empty / non-null entries from the original array.
* In the interest of full disclosure, .NET does have an API that lets you modify array size, but you should not use it in situations like this.
If you are using arrays, you will need to pull the valid values out and put them into a new instance of an array. You can do something like this:
internal static T[] RemoveNullArrayElements<T>(T[] array)
{
if (array != null)
{
List<T> newLst = new List<T>();
foreach (var ar in array)
{
if (ar != null)
{
newLst.Add(ar);
}
}
return newLst.ToArray();
}
return array;
}
Could the problem be that you are searching for white space instead of an empty string?
Try below:
for(int i = 0; i < allToAddresses.Length; i++)
{
if(allToAddresses[i] == "") // find where empty element is
{ //Here i am trying to delete that empty element. does not work
allToAddresses[i].Split("".ToCharArray(),StringSplitOptions.RemoveEmptyEntries);
}
}

Working with arrays and link lists - casting with integers and strings

So I have programmed for about 6 months now and since it is break I am bored and playing around with stuff. I was going over the concepts of arrays again and made an array that produced 50 randoms numbers and used an insertion sort on them to put them in order. Then I started messing with string arrays. string[] array = new string[] { "Ultima Online", "Everquest", "Baldur's Gate", "Diablo I"}; is my string array. To get it to display the entire string I used a linked list (which I am not sure if I had to, my attempts to casting it didn't work i.e Convert.ToString(array) failed). so I have this
static void Main(string[] args)
{
string[] array = new string[] { "Ultima Online", "Everquest", "Baldur's Gate", "Diablo I"};
List<string> list = new List<string>(array);
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
}
This displays the entire array. Then I thought what if I want to remove or add something to it. So, I placed list.RemoveAt(2); above my Console.Writeline(list[i]);
But this did something I didn't expect. It removes everything at and after the 2nd spot in my list. So I assumed RemoveAt() is going to always remove everything after that value that is indicated.
However, list.Remove(2); gives my errors. 1. Argument 1: cannot convert from 'int' to 'string' and then 2. The best overloaded method match...etc.. argument.
Again my casting didn't work. So, I reverted to RemoveAt and thought for a little bit. For some reason I thought if I make an if statement with an equivalent it would work, and it did.
static void Main(string[] args)
{
string[] array = new string[] { "Ultima Online", "Everquest", "Baldur's Gate", "Diablo I" };
List<string> list = new List<string>(array);
for (int i = 0; i < list.Count; i++)
{
if (i == 2)
{
list.RemoveAt(2);
}
Console.WriteLine(list[i]);
}
So, my questions are these:
Why do the exceptions take place at Remove() but not RemoveAt().
Why does this if statement work? I took a shot in the dark at it and it works, I can understand why it works, but then not why a simply RemoveAt() wouldn't work.
Last, is there a better way to convert than a linked list?
Thank you for anyone who answers these question. I am new to programming and I am trying to understand some concepts that flew past me in my book and on MSDN.com and DotPearl...
RemoveAt only removes the element at that index. It does not remove all the elements following it.
Unless.... you place it in a loop.
Which you did.
So your loop did this:
Remove element 2, output element 0
Remove element 2, output element 1
Remove element 2, output element 2
... and so on
This "works" because of this:
for (.....; i < list.Count; ..... )
^-- this ----^
Basically, your loop and list looked like this:
List is "Ultima Online", "Everquest", "Baldur's Gate", "Diablo I" (4 elements, 0-based, elements 0 through 3)
Index is 0, Remove element 2, "Baldur's Gate", Output element 0, "Ultima Online"
Index is 1, still below length (which is now 3), so remove element 2, "Diablo I", output element 1, "Everquest"
Index is 2, which is now equal to length (which is now 2), so exit
You changed the list while enumerating over it, and you changed it every iteration.
The reason why list.Remove(2) doesn't work is because of this:
list.RemoveAt(x) specifies an index, and the element at that index is removed
list.Remove(x) specifies a value, and the first element in the list that has that value will be removed
Now in this case you have said the list is a list of strings, and you ask it to remove an integer. C#/.NET doesn't allow such shenanigans, and thus told you about the problem before even allowing you to run the program.
For more information, check out the documentation of:
List<T>
List<T>.RemoveAt method
List<T>.Remove method
Remove takes a parameter of type T which corresponds to the object you want to remove. In your instance, Remove takes a string parameter which is supposed to correspond with one of the string items in your list (e.g. Ultima Online).
RemoveAt takes an int which corresponds to the index of the item in the list you want to remove. Once removed, everything is "shifted", so that what was at index 3 is now at index 2. When your loop passes over the RemoveAt(2) again, it removes the item that is now at index 2.
Why do the exceptions take place at Remove() but not RemoveAt()?
You get the exception Argument 1: cannot convert from 'int' to 'string' because the method signature is List<T>.Remove<T>(T). It expects a string.. and you're giving it a number.
Why does this if statement work?
Because you're completely free to compare numbers with numbers. Again, you've used RemoveAt here.. which expects a number.. and you've correctly provided one.
Also, a List<T> isn't a linked list. It is in fact a list backed by an array. An important distinction imo.
RemoveAt works by index. Remove is using the types definition of equality. You have a List<string>, the type is string, string does character by character comparison to determine equality, to remove a string you need to do;
list.Remove("Diablo I");
The issue with your RemoveAt getting rid of everything but the first item is well explained by Dave Zych's answer so I won't go into it.
I will talk about you converting to a list and your use of the term "Linked List" though. So firstly, List<T> in .NET is in no way a linked list. It behaved like one in some ways, however it is backed by an array. There is no need for you to convert to it. To print your array you could do either of the following;
for (int i = 0; i < array.Length; i++)
Console.WriteLine(array[i]);
or
Console.WriteLine(String.Join("\n", array));
You could easily "remove" an item by doing;
array[i] = null;
Assuming you haven't done stuff like string temp = array[i] elsewhere before that line you would be setting the final existing reference to that string to null which basically puts in queue to be GC'd.

Displaying strings from Array without repeats

I working on a project in c# asp.net. I would like to randomly display a string from either an array or list, if certain conditions are met, I would like to display another random string that has not been displayed.
EX.
LIST<string> myString = new List<string> {"one", "two", "three", "four", "five"};
or
string[] myString = new[] {"one", "two", "three", "four", "five"};
void btnAnswer_Click(Object sender, EventArgs e)
{
string Next = myString[random.Next(myString.Length)];
if(my condition is met)
{
lbl.Text = Next;
}
}
I can randomly call a string from my list or array, but not sure how to store repeat results. I've tried using an algorithm that jumbles the array and then a counter for the index, but the counter (counter++) seems to add 1 once and then stops. I've tried using a list and removing the string I use, but it seems to repeat after all strings have been used.
If more code is needed I can provide, just need a point in the right direction.
One option is to display one of the random string and store it in a ViewState.
When you come next time again, check whether new random string is already there in ViewState or not. If it is there in ViewState then get another random string.
Couple of options:
Have an array or list which is a copy of the master array, and whenever you choose one, remove it from the array. Once the array is empty, refresh it from the master array.
Similar, just create your array, shuffle it, and start giving out strings by order. so array[0], next would be array[1], and so on, once you reach the end, shuffle and start again.
There are probably others as well :)
Edit:
If I understand correctly from the comments, you are talking about the option where the input is not unique to begin with. If that is the case, you can create your list with a simple linq query to get only unique values (using distinct), guaranteeing no duplicates.
Have a look at this question for an example.
You can copy the indices into a list, it will save memory while allow us to track all the remaining items:
var indices = Enumerable.Range(0,myString.Count).ToList();
//define some method to get next index
public int? NextIndex(){
if(indices.Count == 0) return null;
int i = random.Next(indices.Count);
int k = indices[i];
indices.RemoveAt(i);
return k;
}
if(my condition is met) {
int? nextIndex = NextIndex();
lbl.Text = nextIndex == null ? "" : myString[nextIndex.Value];
}
Note that the Text is set to empty if there won't be no more remaining string, however you can handle that case yourself in another way such as keep the text unchanged.
You could probably do that, but why not get a unique list of strings first?
var uniqueStrings = myString.Distinct().ToList();
Then as you select strings, do a .Remove() on the last randomly selected value from uniqueStrings.
You said that:
I've tried using a list and removing the string I use, but it seems to repeat after all strings have been used.
The problem here is using the same instance of random for your series after you've run out. If you re-instantiate random = new Random(), the variable is re-seeded and you will have totally different results from what was generated before.

How can I get the user to input more than one value at a time in C#

I am prompting the user to enter their first middle and last name in one prompt.
So if they type for example John Ronald Doe, how can I take those values from that one string and assign them to fname, mname, lname, to create a person constructor that takes these values.
Basically my question is how to take multiple values in one prompt for a user and then assign them to different variables for a constructor.
Thank you!
Just grab the line then split on white spaces. You'll have to do some input validation to make sure they actually enter fName mName lName but I'll leave that to you because what you do is dependent on how robust the application needs to be. By that I mean, what happens if the user only enters two words? Do you just assume it's first and last name and set their middle name to String.Empty ? What happens if they enter 4 or 5 words?
string[] tokens = Console.ReadLine().Split(' ');
if (tokens.Length == 3)
{
// do assignment
}
With regard to your comment;
That is more or less correct. Really what's happening is ReadLine() is returning a string. I'm just calling Split(' ') directly on that result. You could break it into two lines if you'd like but there's no reason to. Split(char delimiter) is an instance method in the String class. It takes a char and returns an array of strings. I'm using tokens because it's kind of a common term. The line is build of three tokens, the first, middle, and last names. It's important to understand that I am not adding anything to an array, Split(' ') is returning an array. string[] tokens is just declaring a reference of type string[], I don't have to worry about the size or anything like that.
An example to get an array of ints from the input. Note, if any of the input is not a valid integer this will throw an exception.
int[] myInts = Console.ReadLine.Split(' ').Select(x => int.Parse(x)).ToArray();
In this example I'm using LINQ on the result of the split. Split returns a string array. Select iterates over that array and applies the lambda expression I pass it to each of it's values. It's best to think of x as the current value. The Select call here is roughly equivalent to;
List<int> myInts = new List<int>();
foreach (string s in tokens)
{
myInts.Add(int.Parse(s));
}
int[] myIntArray = myInts.ToArray();
If you can't trust the user input you should use TryParse. I don't know if you can use that as part of a lambda expression (it wouldn't surprise me if you could but it seems like a pain in the ass so I wouldn't bother) instead I'd do;
List<int> myInts = new List<int>();
int temp;
foreach (string s in tokens)
{
if (int.TryParse(s, temp)
myInts.Add(temp);
else
// the input wasn't an int
}
int[] myIntArray = myInts.ToArray();

Format LookUp values, retrieved from WebServices

I am working with Lists WebService and on retrieval of XML data, I need to format it in a nice and clean format to be displayed on front-end. I am getting values of loopup as below format
12;#Infor ERP Baan;#15;#Infor ERP LN;#31;#Infor PM;#32;#Infor SCM
and I need to display it as a bullet list, and for I'll need the values to be just separated by ";" to that I can putt in for loop and add <li>, something like
Infor ERP Baan;Infor ERP LN;Infor PM;Infor SCM
I have used the following function and regular expression to split the data when returning lookup data from SharePoint.
static private Dictionary<int,string> GetValues(string productsCellData)
{
// regular expression to split the data into an array, we need the ExplictCapture
// to prevent c# capturing the ;#
var regex = new Regex(#"((?<=\d);#|;#(?=\d))", RegexOptions.ExplicitCapture);
// our array of data that has been processed.
var productsCellsArray = regex.Split(productsCellData);
Dictionary<int, string> productsDictionary = new Dictionary<int, string>();
if (productsCellsArray.Length % 2 == 1)
{
// handle badly formatted string the array length should always be an even number.
}
// set local variables to hold the data in the loop.
int productKey = -1;
string productValue = string.Empty;
// loop over the array and create our dictionary.
for (var i = 0; i < productsCellsArray.Length; i++)
{
var item = productsCellsArray[i];
// process odd/even
switch (i % 2)
{
case 0:
productKey = Int32.Parse(item);
break;
case 1:
productValue = item;
if (productKey > 0)
{
productsDictionary.Add(productKey, productValue);
productKey = -1;
productValue = string.Empty;
}
break;
}
}
return productsDictionary;
}
This has the advantage of processing the delimiter ;# if it appears (unlikely as it seems) in the value section.
It also has the following advantages
Lookup values from the Id
Get Array of Id's from the dictionary
Get Array of Values from the dictionary
Check if a value exists in the dictionary
Check if an id exists in the dictionary
Hope this helps.
A lookup field value in SharePoint contains two pieces of information - an ID of the item being looked up and the textual value of the referenced field. These are combined together in one string using ;# as a separator.
What you have here, is a value of SPFieldLookupMulti - field where you can have multiple values selected at the moment. Hence, it contains ID1;#value1;#ID2;#value2...
The easiest solution is to String.Split up by ;# substring (see this response to find out, how: https://stackoverflow.com/q/1126933/239599) then access only the even indices of the resulting array: 0th element contains ID1, 1st element contains value1; 2nd element contains ID2; 3rd element contains value2.
So you can use a for loop and increment the counter by 2.
The best way to do this would be :
ProductsCellData = "12;#Infor ERP Baan;#15;#Infor ERP LN;#31;#Infor PM;#32;#Infor SCM"
string[] nProductsCellData = Regex.Replace(ProductsCellData, #"\d", ";").Replace(";#", "").Replace(";;", ";").Split(';');
foreach (string product in nProductsCellData)
{
if (product != "")
{
e.Row.Cells[i].Text += "<li>" + product + "</li>";
}
}

Categories

Resources