Making an array of an unknown size C# [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Array of an unknown length in C#
I want to create a program where users can input there items and those items will be stored in an array. When the user is okay with the amount of items, the program will ask for every item if he got it.
The problem is i cant seem to create an array that is of unknown size. I tried to use something like this: String[] list = new string[]{}; But when the program goes there it gives an IndexOutOfRangeException.
Is there a way i can do this?
This is the full code:
bool groceryListCheck = true;
String[] list = new string[]{};
String item = null;
String yon = null;
int itemscount = 0;
int count = 0;
while (groceryListCheck)
{
Console.WriteLine("What item do you wanna go shop for?");
item = Console.ReadLine();
list[count] = item;
count++;
Console.WriteLine("Done?");
yon = Console.ReadLine();
if (yon == "y")
{
groceryListCheck = false;
itemscount = list.Count();
}
else
{
groceryListCheck = true;
}
}
for (int x = 0; x < itemscount; x++)
{
Console.WriteLine("Did you got the " + list[x] + "?");
Console.ReadKey();
}

Use a List instead of an array.
List<string> myList = new List<string>();
myList.Add("my list item");
After you have gathered all of the items, you can then use a foreach loop to iterate through all of the items in the collection.
foreach(string listItem in myList)
{
Console.WriteLine(listItem);
}

A List<string> would be much easier and more flexible.
There are lots of examples of using a List here which show you a variety of methods to extract data from them.

You can use a List<string> and then, if you need an array as result, you can call the .ToArray() method.

I found that making variable list into a List worked. For instance:
bool groceryListCheck = true;
List<string> list = new List<string>();
String item = null;
String yon = null;
int itemscount = 0;
while (groceryListCheck)
{
Console.WriteLine("What item do you wanna go shop for?");
item = Console.ReadLine();
list.Add(item);
Console.WriteLine("Done?");
yon = Console.ReadLine();
if (yon == "y")
{
groceryListCheck = false;
itemscount = list.Count();
}
else
{
groceryListCheck = true;
}
}
for (int x = 0; x < itemscount; x++)
{
Console.WriteLine("Did you got the " + list[x] + "?");
Console.ReadKey();
}
That is the full code and it works for me.

I would say for this purpose you should use a Hashtable. You can add to it as much as you want and you do not need to specify the size when you create it. Kind of like a really simple database.
See: http://www.dotnetperls.com/hashtable

Related

Finding odd or even in an C# array

I'm supposed to create a method that takes an array and tells if the number is odd or even. I think I'm close to the answer but when I ran the code, it popped up with "Index is outside the bounds of the array". Is there a way to fix that?
private static string OddOrEven(int[] integerArray, string[] numAssign)
{
foreach (int i in integerArray)
{
if (integerArray[i] % 2==0)
{
numAssign[i] = " is even";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
else
{
numAssign[i] = " is odd";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
}
return "";
}
I'm still new to c# so any help is really appreciated.
Your mistake here is with how foreach works. I'll provide a different example to help you understand:
List<Person> people = GetPeople();
foreach (Person p in people)
{
Console.WriteLine(p.Name);
}
As you can see, the variable in the foreach actually receives each item, not its index. It's just that you have a list of int so it's not so obvious for you.
It seems like you want a regular for loop:
for(int i = 0; i < integerArray.Length; ++i)
{
if (integerArray[i] % 2==0)
{
numAssign[i] = " is even";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
else
{
numAssign[i] = " is odd";
string returnValue = integerArray[i] + numAssign[i];
return returnValue;
}
}
The next curious thing is your return returnValue; - the if statement can only ever enter one or the other, so it will always return a string for the first item only. It won't go on to the second, third, fourth, etc. item as it has already left the method before the loop has a chance to move on to the next value.
Speculation
I expect you want an array of results like this:
private static string[] OddOrEven(int[] integerArray)
{
string[] resultValues = new string[integerArray.Length];
for (int i = 0; i < integerArray.Length; ++i)
{
if (integerArray[i] % 2==0)
{
string numAssign = " is even";
resultValues[i] = integerArray[i] + numAssign;
}
else
{
string numAssign = " is odd";
resultValues[i] = integerArray[i] + numAssign;
}
}
return resultValues;
}
Note that I've removed the numAssign incoming array from the method parameters, and now just build it within the method itself.
This would produce a result like this.

Changing the index of arrays

I am stuck at this the following problem. I am trying to create an array with pre-specified size and elements. Later I ask the user to provide me a name they want to add. I then create a new array of one size bigger and add the name new on the last place. Later I ask the user to provide me with a name from the array they wish to remove. And that's where the problem arises. I know I can use the method Array-Copy etc. but I want this to be solved only through index. Here is the code I have written so far:
class Program
{
static void Main(string[] args)
{
string[] names = { "Adam", "Eva" };
foreach (var item in names)
{
Console.WriteLine(item);
}
Console.Write("Skriv in ett namn du vill lägga till: ");
string newAdd = Console.ReadLine();
string[] addedNames = AddName(names, newAdd);
foreach (var item in addedNames)
{
Console.WriteLine(item);
}
Console.Write("Ange det element du vill ta bort: ");
string tabort = Console.ReadLine();
string[] removedNames = RemoveName(addedNames, tabort);
foreach (var item in removedNames)
{
Console.WriteLine(item);
}
}
static string[] AddName(string[] names, string newAdd)
{
string[] newNames = new string[names.Length + 1];
for (int i = 0; i < names.Length; i++)
{
newNames[i] = names[i];
}
newNames[newNames.Length - 1] = newAdd;
return newNames;
}
static string[] RemoveName(string[] addedNames, string tabort)
{
string lLName = tabort.ToLower();
string[] newnames = new string[addedNames.Length - 1];
if (lLName == addedNames[0].ToLower())
{
int index = 0;
for (int i = 1; i < addedNames.Length; i++)
{
newnames[index] = addedNames[i];
index++;
}
}
else if (lLName == addedNames[addedNames.Length-1].ToLower())
{
for (int i = 0; i < addedNames.Length-1; i++)
{
newnames[i] = addedNames[i];
}
}
else if (lLName != addedNames[addedNames.Length-1].ToLower() && lLName != addedNames[0].ToLower())
{
for (int i = 1; i < addedNames.Length; i++)
{
}
}
return newnames;
}
}
}
So you can see that I am trying to implement the last else if statement, but I am not sure how to deal when the name provided by the user appears somewhere in my addedNames array except on the first and last places.
I would also love if you think there is an easier way to deal with the problem instead haveing almost 4 if statements for each case. It seems for me that if one manages to implement the last if statement then it will work regardless where the name, provided by the user to be removed, iss located in the addedNames array.
Why not just find the index of the name that needs to be replaced (tabort), and just change the value to newAdd?
string newAdd = Console.ReadLine();
string tabort = Console.ReadLine();
int i = Array.FindIndex(names, x => x.Contains(tabort));
names[i] = newAdd;

C# Variable not getting all values outside for loop

I have two values in the dictionary but when I try to get the two values outside the loop I am only getting one value. The locationdesc variable value are being overwritten. Is there a better way to create unique variables to handle this issues
There are two keys location-1 and location-2. I am trying to figure out how to get both the values outside the loop. Am I doing it wrong?
string locationDesc = "";
string locationAddress = "";
int count = dictionary.Count(D => D.Key.StartsWith("location-"));
for (int i = 1; i <= count; i++)
{
if (dictionary.ContainsKey("location-"+i))
{
string locationData = dictionary["location-"+i];
string[] locationDataRow = locationData.Split(':');
locationDesc = locationDataRow[0];
locationAddress = locationDataRow[1];
}
}
// Only getting location-2 value outside this loop since locationDesc is not unique.
Debug.WriteLine("Location Desc from dictionary is : " + locationDesc);
Debug.WriteLine("Location Add from dictionary is : " + locationAddress);
What I would like to get here is get both the values like locationDesc1 and locationDesc2 instead of locationDesc
What I am looking for is to create locationDesc and locationAddress unique so I can access both the values outside the for loop.
More Explanation as I was not very clear:
I have a dynamic table that will be created in the front end. Every time a location is created I create a cookie. For e.g. location-1, location-2 ...location-n with the location description and location values as values in the cookie. I am trying to access these values in the backend by creating a dictionary so I can assign all the values to unique variable which will make it easier for me to pass these values to a api call. I think I am over complicating a simple issue and might be doing it wrong.
My api call will be something like this:
<field="" path="" value=locationDesc1>
<field="" path="" value=locationDesc2>
The problem with your loop is that you are relying on the position of the entry in the dictionary matching the index within your loop. Your first line of code pretty much has it though:
int count = dictionary.Count(D => D.Key.StartsWith("location-"));
What this tells me is that you are looking for all entries in your dictionary where the key starts with "location-". So why not do that directly:
var values = dictionary.Where(d => d.Key.StartsWith("location-"));
And to do the extraction/string splitting at the same time:
var values = dictionary
.Where(d => d.Key.StartsWith("location-"))
.Select(d => d.Item.Split(':')
.Select(s => new
{
LocationDesc = s[0],
LocationAddress = s[1]
});
This will give you an IEnumerable of LocationDesc/LocationAddress pairs which you can loop over:
foreach(var pair in values)
{
Debug.WriteLine(pair.LocationDesc);
Debug.WriteLine(pair.LocationAddress);
}
Try this:
int count = dictionary.Count(D => D.Key.StartsWith("location-"));
Dictionary<string, string> values = new Dictionary<string, string>();
for (int i = 1; i <= count; i++)
{
if (dictionary.ContainsKey("location-"+i))
{
string locationData = dictionary["location-"+i];
string[] locationDataRow = locationData.Split(':');
values.Add(locationDataRow[0],locationDataRow[1]);
}
}
foreach (var item in values)
{
Debug.WriteLine(item.Key + " : " + item.Value);
}
As you are dealing with multiple values, you should go with a container where you can store all the values.
if you are dealing with only two unique values then use below code.
int count = dictionary.Count(D => D.Key.StartsWith("location-"));
string[] locationDesc = new string[2];
string[] locationAddress = new string[2];
for (int i = 1; i <= count; i++)
{
if (dictionary.ContainsKey("location-"+i))
{
string locationData = dictionary["location-"+i];
string[] locationDataRow = locationData.Split(':');
locationDesc[i-1] = locationDataRow[0];
locationAddress[i-1] = locationDataRow[1];
}
}
for (int i = 0; i <= locationDesc.Length-1; i++)
{
Debug.WriteLine("Location Desc from dictionary is : " + locationDesc[i]);
Debug.WriteLine("Location Add from dictionary is : " + locationAddress[i]);
}
if number of unique values is not fixed then go with ArrayList
int count = dictionary.Count(D => D.Key.StartsWith("location-"));
ArrayList locationDesc = new ArrayList();
ArrayList locationAddress = new ArrayList();
for (int i = 1; i <= count; i++)
{
if (dictionary.ContainsKey("location-"+i))
{
string locationData = dictionary["location-"+i];
string[] locationDataRow = locationData.Split(':');
locationDesc.Add(locationDataRow[0]);
locationAddress.Add(locationDataRow[1]);
}
}
for (int i = 0; i < locationDesc.Count; i++)
{
Debug.WriteLine("Location Desc from dictionary is : " + locationDesc[i]);
Debug.WriteLine("Location Add from dictionary is : " + locationAddress[i]);
}
Simple One. If you only want to show result using Debug.WriteLine, then go with below code
int count = dictionary.Count(D => D.Key.StartsWith("location-"));
for (int i = 1; i <= count; i++)
{
if (dictionary.ContainsKey("location-"+i))
{
string locationData = dictionary["location-"+i];
string[] locationDataRow = locationData.Split(':');
Debug.WriteLine("Location Desc from dictionary is : " + locationDataRow[0]);
Debug.WriteLine("Location Add from dictionary is : " + locationDataRow[1]);
}
}
Not able to prepare Code in Visual Studio at the moment therefore there may be some syntax errors.
It is hard to judge what you are event trying to do. I would not just be dumping objects you already have into other objects for fun. If you are just trying to expose values in a loop for use with another function, you can just use LINQ to iterate over the dictionary. If you want a specific value just add a where LINQ expression. LINQ should be in any .NET framework after 3.5 I believe.
public static void ApiMock(string s)
{
Console.WriteLine($"I worked on {s}!");
}
static void Main(string[] args)
{
var d = new Dictionary<int, string> {
{ 1, "location-1" },
{ 2, "location-2" },
{ 3, "location-3" }
};
d.ToList().ForEach(x => ApiMock(x.Value));
//I just want the second one
d.Where(x => x.Value.Contains("-2")).ToList().ForEach(x => ApiMock(x.Value));
//Do you want a concatenated string
var holder = string.Empty;
d.ToList().ForEach(x => holder += x.Value + ", ");
holder = holder.Substring(0, holder.Length - 2);
Console.WriteLine(holder);
}

How to implement C# code for Order id separated by commas and range separated by hyphens, and display all info of order

Ex: 1,4-90, 292,123
It needs to display the whole order information of
1
4,5,6....90
292
123.
Whats the gud approach to solve this.
It is similar to tracking in UPS or fedex if multiple orders are given in search box.
I meant if in a search box I giv 1,4-90, 292,123 this string the result that needs to come back is a grid representation of all the data which is corresponding to each of the order id respectively. I want to know how to parse the string into collection and send them to the database and show the information in the grid for...
1
4,5,6....90
292
123.
as a different row...from where I can generate reports too (alternative)
Please try.
static ArrayList list;
static void Main(string[] args)
{
string str = "1,4-90,292,123";
string[] arr = str.Split(',');
list = new ArrayList();
for (int i = 0; i < arr.Length; i++)
{
string tmp = arr[i];
if (tmp.IndexOf('-') != -1)
{
Range(tmp);
}
else list.Add(int.Parse(tmp));
}
list.Sort();
object[] intResult = list.ToArray();
//print the final result
for (int i = 0; i < intResult.Length; i++)
{
Console.WriteLine(intResult[i].ToString());
}
Console.Read();
}
static void Range(string range)
{
string[] tmpArr = range.Split('-');
int stInt = int.Parse(tmpArr[0]);
int edInt = int.Parse(tmpArr[1]);
int[] intArr = new int[(edInt - stInt) + 1];
for (int i = 0; stInt <= edInt; i++)
{
list.Add(stInt++);
}
}

How to set array length in c# dynamically

I am still new to C# and I've been struggling with various issues on arrays. I've got an array of metadata objects (name value pairs) and I would like to know how to create only the number of "InputProperty" objects that I truly need. In this loop I've arbitrarily set the number of elements to 20 and I try to bail out when the entry becomes null but the web service on the receiving end of this does not like any null elements passed to it:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
InputProperty[] ip = new InputProperty[20]; // how to make this "dynamic"
int i;
for (i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
update.Items = ip;
return update;
}
In summary, say I only have 3 namevalue pairs in the above input array? Rather than allocate 20 elements for the array called ip, how can code this so ip is only as big as it needs to be. The update object is passed across another webservice so serialization is important (i.e. I can't use namevaluecollection, etc.).
p.s. Is the only way to followup on a posted question through the "add comments" facility?
InputProperty[] ip = new InputProperty[nvPairs.Length];
Or, you can use a list like so:
List<InputProperty> list = new List<InputProperty>();
InputProperty ip = new (..);
list.Add(ip);
update.items = list.ToArray();
Another thing I'd like to point out, in C# you can delcare your int variable use in a for loop right inside the loop:
for(int i = 0; i<nvPairs.Length;i++
{
.
.
}
And just because I'm in the mood, here's a cleaner way to do this method IMO:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
var ip = new List<InputProperty>();
foreach(var nvPair in nvPairs)
{
if (nvPair == null) break;
var inputProp = new InputProperty
{
Name = "udf:" + nvPair.Name,
Val = nvPair.Value
};
ip.Add(inputProp);
}
update.Items = ip.ToArray();
return update;
}
If you don't want to use a List, ArrayList, or other dynamically-sized collection and then convert to an array (that's the method I'd recommend, by the way), then you'll have to allocate the array to its maximum possible size, keep track of how many items you put in it, and then create a new array with just those items in it:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
InputProperty[] ip = new InputProperty[20]; // how to make this "dynamic"
int i;
for (i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
if (i < nvPairs.Length)
{
// Create new, smaller, array to hold the items we processed.
update.Items = new InputProperty[i];
Array.Copy(ip, update.Items, i);
}
else
{
update.Items = ip;
}
return update;
}
An alternate method would be to always assign update.Items = ip; and then resize if necessary:
update.Items = ip;
if (i < nvPairs.Length)
{
Array.Resize(update.Items, i);
}
It's less code, but will likely end up doing the same amount of work (i.e. creating a new array and copying the old items).
Use this:
Array.Resize(ref myArr, myArr.Length + 5);
Does is need to be an array? If you use an ArrayList or one of the other objects available in C#, you won't have this limitation to content with. Hashtable, IDictionnary, IList, etc.. all allow a dynamic number of elements.
You could use List inside the method and transform it to an array at the end. But i think if we talk about an max-value of 20, your code is faster.
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
List<InputProperty> ip = new List<InputProperty>();
for (int i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
update.Items = ip.ToArray();
return update;
}
Or in C# 3.0 using System.Linq you can skip the intermediate list:
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
var ip = from nv in nvPairs
select new InputProperty()
{
Name = "udf:" + nv.Name,
Val = nv.Value
};
update.Items = ip.ToArray();
return update;
}
Use Array.CreateInstance to create an array dynamically.
private Update BuildMetaData(MetaData[] nvPairs)
{
Update update = new Update();
InputProperty[] ip = Array.CreateInstance(typeof(InputProperty), nvPairs.Count()) as InputProperty[];
int i;
for (i = 0; i < nvPairs.Length; i++)
{
if (nvPairs[i] == null) break;
ip[i] = new InputProperty();
ip[i].Name = "udf:" + nvPairs[i].Name;
ip[i].Val = nvPairs[i].Value;
}
update.Items = ip;
return update;
}
Typically, arrays require constants to initialize their size. You could sweep over nvPairs once to get the length, then "dynamically" create an array using a variable for length like this.
InputProperty[] ip = (InputProperty[])Array.CreateInstance(typeof(InputProperty), length);
I wouldn't recommend it, though. Just stick with the
List<InputProperty> ip = ...
...
update.Items = ip.ToArray();
solution. It's not that much less performant, and way better looking.
You can create an array dynamically in this way:
static void Main()
{
// Create a string array 2 elements in length:
int arrayLength = 2;
Array dynamicArray = Array.CreateInstance(typeof(int), arrayLength);
dynamicArray.SetValue(234, 0); // → a[0] = 234;
dynamicArray.SetValue(444, 1); // → a[1] = 444;
int number = (int)dynamicArray.GetValue(0); // → number = a[0];
int[] cSharpArray = (int[])dynamicArray;
int s2 = cSharpArray[0];
}

Categories

Resources