I'm after some advice on the most efficient approach to stepping through a list of fields and filling in their values to a class object.
I currently accessing fields via (code isn't exact but you get the idea =] ):
private string fieldName;
private int fillValue;
SessionData rawdata = new SessionData();
var count = 1;
foreach (objecttype obj in list)
{
fillValue = obj.valueA + obj.ValueB;
if (count < 10)
{
fieldName = "band0" + count;
}
else
{
fieldName = "band" + count;
}
rawdata.GetType().GetProperty(fieldName).SetValue(rawdata, fillValue , null);
count++;
}
This is the basic idea of how I'm filling fields "band01" to "band99" (for example) with values 1-99.
Is there any other more effective method for doing this besides writing an individula if statement for each field?
Thanks for your time.
Instead of the if statement, use
fieldName = String.Format( "band{0:00}", count)
fieldName = "band" + count.ToString("00");
Related
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.
I was wondering whether there's a way in a "for" loop to assign a value to a string variable named according to its index number?
let's say I have 3 string variables called:
string message1 = null;
string message2 = null;
string message3 = null;
And I want the 'for' loop to do the something like the following code:
for (int i = 1; i <=3; i++)
{
messagei = "blabla" + i.ToString();
}
I don't want to use an "if" or a "switch" because it will make the code harder to follow.
Is there a way to do that?
You don't want 3 variables with the same name, you want an array of those variables.
string[] messages = new string[3]; // 3 item array
You can then store your items in the array elements
messages[0] = "Apple"; // array index starts at 0!
messages[1] = "Banana";
messages[2] = "Cherry";
Another way to create that array is an inline array initializer, saves some code
string[] messages = { "Apple", "Banana", "Cherry" };
(Note: there are more valid syntaxes for array initialization. Research on the various other methods is left as an exercise.)
And access them via a loop (foreach)
foreach (string fruit in messages)
{
Console.WriteLine("I'm eating a " + fruit);
}
Or for
for (int i = 0; i < messages.Length; i++)
{
Console.WriteLine("I'm eating a " + messages[i]); // reading the value
messages[i] = "blabla" + i.ToString(); // writing a value to the array
}
can you use an array? or list type?
string[] messages = new string[3];
for (int i = 1; i <=3; i++)
{
messages[i] = "blabla" + i.ToString();
}
You said you don't want to have a switch statement. I realize this does have a switch, but if you must have three different variables, you could encapsulate your switch inside a function call:
string message1 = null;
string message2 = null;
string message3 = null;
void SetMessage(int i, string value)
{
if(i == 1)
message1 = value;
etc
}
for (int i = 1; i <=3; i++)
{
SetMessage(i, "blabla" + i.ToString());
}
Not an optimal solution but if you MUST have separate variables it will hide the mess.
You can't do that (well, not sanely). Have you considered using an array of strings instead?
I think you should use an array for this kind of variables.
string[] message = new string[3];
for (int i = 1; i <=3; i++)
{
message[i] = "blabla" + i.ToString();
}
Usually instead of having N differents variables named 1, 2, ..., N the way is to store them in an array:
string message[3];
message[0] = null;
message[1] = null;
message[2] = null;
and then the loop:
for (int i = 0; i <=2; i++)
{
message[i] = "blabla" + i.ToString();
}
Note that, usually again, a set of indexed variables starts with value 0 ;)
I would go about it a little differently, maybe use a dictionary and store your messages. Something like this:
Dictionary<string, string> messages = new Dictionary<string, string>();
for(int i = 1; i <= 3; i++)
{
messages.Add("message" + i.ToString(), i.ToString());
}
You can also do it without the index:
string[] Messages = { "Tom", "Dick", "Harry" };
foreach (String Message in Messages)
{
Response.Write("Hello " + Message + "<br />");
}
If you declare your variable in a class as public variables, you can access them as follow;
public partial class _Default : System.Web.UI.Page
{
public string message1 = null;
public string message2 = null;
public string message3 = null;
public void setVars()
{
for (int i = 1; i <=3; i++)
{
this.GetType().GetField("message" + i.ToString()).SetValue(this, "blabla" + i.ToString());
}
}
}
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);
}
First time on stackOverflow, so this might be a really nooby question, but i was wondering if i could change multiple variable values at the same time without having to write out every single one.
Here is my code at the moment:
public string Label1Text()
{
int index;
for (index = 0; index < 32; index++)
{
if (seatChosen[index])
{
_bookedSeats += "A" + (index + 1) + " ";
Properties.Settings.Default.A1 = true;
}
}
string text = _bookedSeats + ".";
//debug
label1.Text = text;
return text;
}
The line
Properties.Settings.Default.A1 = true;
is what i want to change to something like this (theoretical code)
Properties.Settings.Default.A[index] = true;
or
Properties.Settings.Default.A + index = true;
I hope you can understand what I'm trying to accomplish.
Using reflection: (I'm assuming Properties.Settings.Default is a static class, and A1, A2, etc. are public static properties.)
Type type = typeof(Properties.Settings.Default);
var prop = type.GetProperty(index.ToString("\\A0"));
if (prop != null)
prop.SetValue(null, true);
If Default is an instance, you would need to pass it to SetValue instead of null. Also, C# v6 allows a more concise syntax.
Type type = Properties.Settings.Default.GetType();
type.GetProperty($"A{index}")?.SetValue(Properties.Settings.Default, true);
I have a large list and I would like to overwrite one value if required. To do this, I create two subsets of the list which seems to give me an OutOfMemoryException. Here is my code snippet:
if (ownRG != "")
{
List<string> maclist = ownRG.Split(',').ToList();
List<IVFile> temp = powlist.Where(a => maclist.Contains(a.Machine)).ToList();
powlist = powlist.Where(a => !maclist.Contains(a.Machine)).ToList(); // OOME Here
temp.ForEach(a => { a.ReportingGroup = ownRG; });
powlist.AddRange(temp);
}
Essentially I'm splitting the list into the part that needs updating and the part that doesn't, then I perform the update and put the list back together. This works fine for smaller lists, but breaks with an OutOfMemoryException on the third row within the if for a large list. Can I make this more efficient?
NOTE
powlist is the large list (>1m) items. maclist only has between 1 and 10 but even with 1 item this breaks.
Solving your issue
Here is how to rearrange your code using the enumerator code from my answer:
if (!string.IsNullOrEmpty(ownRG))
{
var maclist = new CommaSeparatedStringEnumerable(str);
var temp = powlist.Where(a => maclist.Contains(a.Machine));
foreach (var p in temp)
{
p.ReportingGroup = ownRG;
}
}
You should not use ToList in your code.
You don't need to remove thee contents of temp from powlist (you are re-adding them anyway)
Streaming over a large comma-separated string
You can iterate over the list manually instead of doing what you do now, by looking for , characters and remembering the position of the last found one and the one before. This will definitely make your app work because then it won't need to store the entire set in the memory at once.
Code example:
var str = "aaa,bbb,ccc";
var previousComma = -1;
var currentComma = 0;
for (; (currentComma = str.IndexOf(',', previousComma + 1)) != -1; previousComma = currentComma)
{
var currentItem = str.Substring(previousComma + 1, currentComma - previousComma - 1);
Console.WriteLine(currentItem);
}
var lastItem = str.Substring(previousComma + 1);
Console.WriteLine(lastItem);
Custom iterator
If you want to do it 'properly' in a fancy way, you can even write a custom enumerator:
public class CommaSeparatedStringEnumerator : IEnumerator<string>
{
int previousComma = -1;
int currentComma = -1;
string bigString = null;
bool atEnd = false;
public CommaSeparatedStringEnumerator(string s)
{
if (s == null)
throw new ArgumentNullException("s");
bigString = s;
this.Reset();
}
public string Current { get; private set; }
public void Dispose() { /* No need to do anything here */ }
object IEnumerator.Current { get { return this.Current; } }
public bool MoveNext()
{
if (atEnd)
return false;
atEnd = (currentComma = bigString.IndexOf(',', previousComma + 1)) == -1;
if (!atEnd)
Current = bigString.Substring(previousComma + 1, currentComma - previousComma - 1);
else
Current = bigString.Substring(previousComma + 1);
previousComma = currentComma;
return true;
}
public void Reset()
{
previousComma = -1;
currentComma = -1;
atEnd = false;
this.Current = null;
}
}
public class CommaSeparatedStringEnumerable : IEnumerable<string>
{
string bigString = null;
public CommaSeparatedStringEnumerable(string s)
{
if (s == null)
throw new ArgumentNullException("s");
bigString = s;
}
public IEnumerator<string> GetEnumerator()
{
return new CommaSeparatedStringEnumerator(bigString);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Then you can iterate over it like this:
var str = "aaa,bbb,ccc";
var enumerable = new CommaSeparatedStringEnumerable(str);
foreach (var item in enumerable)
{
Console.WriteLine(item);
}
Other thoughts
Can I make this more efficient?
Yes, you can. I suggest to either work with a more efficient data format (you can take a look around databases or XML, JSON, etc. depending on your needs). If you really want to work with comma-separated items, see my code examples above.
There's no need to create a bunch of sub-lists from powlist and reconstruct it. Simply loop over the powlist and update the ReportingGroup property accordingly.
var maclist = new HashSet<string>( ownRG.Split(',') );
foreach( var item in powlist) {
if( maclist.Contains( item.Machine ) ){
item.ReportingGroup = ownRG;
}
}
Since this changes powlist in place, you won't allocate any extra memory and shouldn't run into an OutOfMemoryException.
In a loop find the next ',' char. Take the substring between the ',' and the previous ',' position. At the end of the loop save a reference to the previous ',' position (which is initially set to 0). So you parse the items one-by-one rather than all at once.
You can try looping the items of your lists, but this will increase processing time.
foreach(var item in powlist)
{
//do your opeartions
}