If a class contains just string array variables, is there an easy way to initialize them all without having to type the same code over and over?
For example, if I have something like
[Serializable]
public class ReadDiagnosticEntirePointValuesResponse
{
public string[] pointidentifier;
public string[] presentvalue;
public string[] priorityarray;
public string[] alarmstate;
public string[] outofservice;
public string[] correctvalue;
public string[] affect;
public string[] covenable;
public string[] covincrement;
public string[] covtarget;
public string[] covlifetime;
public string[] historyenable;
public string[] historyincrement;
public string[] elapsedactivetime;
public string[] feedbackvalue;
public string[] rawvalue;
...//A lot more
}
and I want to assign values to to them, I want to avoid doing:
ReadDiagnosticEntirePointValuesResponse response = new ReadDiagnosticEntirePointValuesResponse();
response.affect = new string[count];
response.alarmstate = new string[count];
response.correctvalue = new string[count];
response.covenable = new string[count];
response.covincrement = new string[count];
response.covlifetime = new string[count];
response.covtarget = new string[count];
response.elapsedactivetime = new string[count];
response.feedbackvalue = new string[count];
response.historyenable = new string[count];
response.historyincrement = new string[count];
response.outofservice = new string[count];
response.pointidentifier = new string[count];
response.presentvalue = new string[count];
response.priorityarray = new string[count];
response.rawvalue = new string[count];
...
Sure, I could write those initialization in constructor but that still doesn't save me from having to manually initialize them all.
What's a good way to avoid this?
That is a pretty horrible way to manage your data, however, something like the following would work....
foreach(var field in GetType().GetFields()) {
if(!field.IsStatic) field.SetValue(this, new string[count]);
}
However! I strongly suggest you rethink this design. A better mechanism would be:
class DiagnosticPoint // TODO: rename as appropriate
{ // TODO: check these all need to be strings
public string Affect {get;set;}
public string AlarmState {get;set;}
...
public string RawValue {get;set;}
}
and have an array of that as a field:
public class ReadDiagnosticEntirePointValuesResponse
{
DiagnosticPoint[] points;
...
then simply init the array:
points = new DiagnosticPoint[count];
and init each:
for(int i = 0 ; i < count ; i++) points[i] = new DiagnosticPoint();
and access via:
var alarm = points[index].AlarmState;
(etc)
You can use Reflection to do this:
public ReadDiagnosticEntirePointValuesResponse()
{
GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)
.ToList()
.ForEach(field => field.SetValue(this, new string[count]));
}
At least once you have to initialize them manually. if C'tor doesn't suit you, initialize in a new method.
You might want to look at reflection for that... Reading the class' proprties in a loop
This sounds like an awful class definition. Perhaps using an enum might be better.
If you could start with this:
public enum ReadDiagnostic
{
pointidentifier,
presentvalue,
priorityarray,
alarmstate,
outofservice,
correctvalue,
affect,
covenable,
covincrement,
covtarget,
covlifetime,
historyenable,
historyincrement,
elapsedactivetime,
feedbackvalue,
rawvalue,
}
You could then create a Dictionary<ReadDiagnostic, string[]> to hold your values that you were storing in your class.
You could even use LINQ to create your dictionary in one line of code:
var readDiagnosticEntirePointValues =
typeof(ReadDiagnostic)
.GetEnumValues()
.Cast<ReadDiagnostic>()
.ToDictionary(x => x, x => new string[count]);
This approach is still strongly-typed, but much easier to maintain than your current approach.
You could use the following:
response.affect = response.alarmstate = response... = new string[count];
However, using this will still have you initialize them manually. It's just a shortcut.
As others may already have suggested, using Collection Classes will make it a lot easier. I would recommend a Dictionary. Here is how you could implement it:
enum Foo { Affect, AlarmState, CorrectValue, ... }
public void InitializeArrays(int count)
{
Dictionary<Foo, string[]> response = new Dictionary<Foo, string[]>();
// easy initialization of string arrays
foreach (Foo foo in Enum.GetValues(typeof(Foo)))
{
response.Add(foo, new string[count]);
}
// use this to access the string arrays
response[Foo.Affect][0] = "test";
if (response[Foo.CorrectValue].Length > 0) { ... }
}
Alternatively, you could also achieve the same by using a Multidimensional Array.
// initialize it like this
string[,] response = new string[Enum.GetValues(typeof(Foo)).Length, count];
// access it like this
response[(int)Foo.Affect, 0] = "test";
You can use the array list to avoid of declaring the size.
Related
Queues:
public class Queue
{
public Queue() { }
public process Front() { return this.q_list.ElementAt(0); }
public int Size { get { return this.q_list.Count; } }
public bool IsEmpty { get { return this.q_list.Count <= 0 ? true : false; } }
public void Enqueue(process proc) { this.q_list.Add(proc); }
public void Dequeue() { this.q_list.RemoveAt(0); }
public List<process> q_list = new List<process>();
};
Creation of a list:
List<Queue> rr_list = new List<Queue>();
The process struct:
public class process
{
public int Proc_a;
public int Proc_b;
public int Proc_Index;
};
Let's say I want to add a process to the list at a specific location depending on the value of Proc_Index. How can I do that? Let's also assume the list is initially empty.
process proc = new process{
Proc_a = 1,
Proc_b = 2,
Proc_Index = 4 };
I want to add that to a queue that is in the list located at index 4.
Is this possible?
I've tried:
rr_list[proc.Proc_Index].Enqueue(proc);
But it says there's an issue with index not being found or something.
The only thing I can thing of is initializing the list by adding empty queues for up to 20 indexes, but I don't know if there's a better way.
You should use a System.Collections.Generic.Queue instead of writing your own. Use a System.Collections.Generic.Dictionary if you want key-value lookup.
var rr_list = new Dictionary<int, Queue<process>>();
process proc = new process{
Proc_a = 1,
Proc_b = 2,
Proc_Index = 4 };
rr_list[proc.Proc_Index].Enqueue(proc);
You may want to use a dictionary instead of a list.
var rr_list = new Dictionary<int, Queue>();
Then have an addprocess function as such
function void AddProcess(proccess proc){
if(rr_list.ContainsKey(proc.Proc_Index){
rr_list[proc.Proc_Index].Enqueue(proc);
} else {
rr_list[proc.Proc_Index] = (new Queue()).Enqueue(proc);
}
}
A list is usually supposed to have no holes, so if you were to add an element at index 4 to an empty list, this would make indexes 0 to 3 contain null.
Now, you can do it like that. You could check if the length is bigger than the requested index, and if not, keep adding null values until it is. Then the index would exist, and you could assign something to it:
static void EnsureLength<T> (List<T> list, int index)
{
while (list.Count <= index)
list.Add(default(T));
}
Then you could use it like this:
List<int?> list = new List<int?>();
EnsureLength(list, 3);
list[3] = 123;
A possibly better way would be to simply use a Dictionary, especially if you know that you will have holes. So you would just have a Dictionary<int, T>:
Dictionary<int, int?> dict = new Dictionary<int, int?>();
dict[3] = 123;
I've the following class:
class Node
{
public string NameField{ get; set; }
public string ValueField{ get; set; }
}
And also have a list of Nodes as var test = new List<Node>, I need to make two strings arrays as string[], first contains all the NameField and the second contains all the ValueField, I did the following code:
string[] NameField = new string[test.Count];
string[] ValueField = new string[test.Count];
int i = 0;
foreach (var s in prefsNameValueArray)
{
NameField[i] = s.CTMAttrName;
ValueField[i] = s.CTMAttrValue;
i++;
}
Can I do the same using LINQ, can anybody help me to improve this code?
Thanks in advance,
Ramzy
With Linq:
string[] NameFields = nodes.Select(n => n.NameField).ToArray();
string[] ValueFields = nodes.Select(n => n.ValueField).ToArray();
Linq is not necessarily the most efficient way here since ToArray could create an array which may be too large(due to the doubling algorithm) if you use a query instead of a collection. But it is short and readable (and fast enough mostly).
This is the for-loop version:
int count = nodes.Count(); // in case you want to change the collection type or use a linq query
string[] NameField = new string[count];
string[] ValueField = new string[count];
for (int i = 0; i < count; i++)
{
NameField[i] = nodes.ElementAt(i).NameField;
ValueField[i] = nodes.ElementAt(i).ValueField;
}
var nameField = test.Select(n => n.CTMAttrName).ToArray();
var valueField = test.Select(n => n.CTMAttrValue).ToArray();
Using Lambda expressions;
string[] NameField = prefsNameValueArray.Select(x=> x.NameField).ToArray();
string[] ValueField = prefsNameValueArray.Select(x=> x.ValueField).ToArray();
Maybe I asked this is a bad way so let me try to explain.
I have a public static string[]
public static string[] MyInfo {get;set;}
I set this via
MyInfo = File.ReadAllLines(#"C:\myfile.txt");
What I want to do is a foreach on each of those lines and modify it based on x number of rules. One the line has been modified change that exisiting line in MyInFo
so
foreach(string myI in MyInfo)
{
string modifiedLine = formatLineHere(myI);
//return this to MyInfo somehow.
}
You can't do this in a foreach loop. Use for instead.
Use a for:
for(int i = 0; i < MyInfo.Length; i++)
{
MyInfo[i] = formatLineHere(MyInfo[i]);
}
var myInfoList = new List<string>();
foreach (var myI in MyInfo)
{
var modifiedLine = formatLineHere(myI);
myInfoList.Add(modifiedLine);
}
MyInfo = myInfoList.ToArray();
Update
You will need a reference to System.Linq in order to use the ToList() and ToArray() extension methods.
Or with Linq you could do:
MyInfo = MyInfo.Select(x => formatLineHere(x)).ToArray();
For example
MYCLASS[] myclass = new MYCLASS[10];
Now myclass array is all null array but i want to have default constructed Array .I know that i can write loops for set default constructed but i am looking for more easy and simple way.
If you don't want to write out the loop you could use Enumerable.Range instead:
MyClass[] a = Enumerable.Range(0, 10)
.Select(x => new MyClass())
.ToArray();
Note: it is considerably slower than the method you mentioned using a loop, written here for clarity:
MyClass[] a = new MyClass[10];
for (int i = 0; i < a.Length; ++i)
{
a[i] = new MyClass();
}
var a = Enumerable.Repeat(new MYCLASS(), 10).ToArray();
There isn't an easier way. If you just don't like loops, you could use
MyClass[] array = new[] { new MyClass(), new MyClass(), new MyClass(), new MyClass() };
which would give you an array with 4 elements of type MyClass, constructed with the default constructor.
Otherwise, you just have the option to use a loop.
If you don't want to write that loop every time you want to construct your array, you could create a helper-method, for example as an extension method:
static class Extension
{
public static void ConstructArray<T>(this T[] objArray) where T : new()
{
for (int i = 0; i < objArray.Length; i++)
objArray[i] = new T();
}
}
And then use it like this:
MyClass[] array = new MyClass[10];
array.ConstructArray();
There isn't really a better way. You could do something like:
public static T[] CreateArray<T>(int len) where T : class, new() {
T[] arr = new T[len];
for(int i = 0 ; i <arr.Length ; i++) { arr[i] = new T(); }
return arr;
}
then at least you only need:
Foo[] data = CreateArray<Foo>(150);
This approach should at least avoid any reallocations, and can use the JIT array/length optimisation. The : class is to avoid use with value-types, as with value-types already initialize in this way; just new MyValueType[200] would be better.
You can use LINQ.
var a = (from x in Enumerable.Range(10) select new MyClass()).ToArray();
If we want to do all job in only one line code so this is best
MYCLASS[] myclass = (new MYCLASS[10]).Select(x => new MYCLASS()).ToArray();
Is it possible to create a multidimensional list in C#?
I can create an multidimensional array like so:
string[,] results = new string[20, 2];
But I would like to be able to use some of the features in a list or arraylist like being able to add and delete elements.
You can create a list of lists
public class MultiDimList: List<List<string>> { }
or a Dictionary of key-accessible Lists
public class MultiDimDictList: Dictionary<string, List<int>> { }
MultiDimDictList myDicList = new MultiDimDictList ();
myDicList.Add("ages", new List<int>());
myDicList.Add("Salaries", new List<int>());
myDicList.Add("AccountIds", new List<int>());
Generic versions, to implement suggestion in comment from #user420667
public class MultiDimList<T>: List<List<T>> { }
and for the dictionary,
public class MultiDimDictList<K, T>: Dictionary<K, List<T>> { }
// to use it, in client code
var myDicList = new MultiDimDictList<string, int> ();
myDicList.Add("ages", new List<T>());
myDicList["ages"].Add(23);
myDicList["ages"].Add(32);
myDicList["ages"].Add(18);
myDicList.Add("salaries", new List<T>());
myDicList["salaries"].Add(80000);
myDicList["salaries"].Add(100000);
myDicList.Add("accountIds", new List<T>());
myDicList["accountIds"].Add(321123);
myDicList["accountIds"].Add(342653);
or, even better, ...
public class MultiDimDictList<K, T>: Dictionary<K, List<T>>
{
public void Add(K key, T addObject)
{
if(!ContainsKey(key)) Add(key, new List<T>());
if (!base[key].Contains(addObject)) base[key].Add(addObject);
}
}
// and to use it, in client code
var myDicList = new MultiDimDictList<string, int> ();
myDicList.Add("ages", 23);
myDicList.Add("ages", 32);
myDicList.Add("ages", 18);
myDicList.Add("salaries", 80000);
myDicList.Add("salaries", 110000);
myDicList.Add("accountIds", 321123);
myDicList.Add("accountIds", 342653);
EDIT: to include an Add() method for nested instance:
public class NestedMultiDimDictList<K, K2, T>:
MultiDimDictList<K, MultiDimDictList<K2, T>>:
{
public void Add(K key, K2 key2, T addObject)
{
if(!ContainsKey(key)) Add(key,
new MultiDimDictList<K2, T>());
if (!base[key].Contains(key2))
base[key].Add(key2, addObject);
}
}
you just make a list of lists like so:
List<List<string>> results = new List<List<string>>();
and then it's just a matter of using the functionality you want
results.Add(new List<string>()); //adds a new list to your list of lists
results[0].Add("this is a string"); //adds a string to the first list
results[0][0]; //gets the first string in your first list
Not exactly. But you can create a list of lists:
var ll = new List<List<int>>();
for(int i = 0; i < 10; ++i) {
var l = new List<int>();
ll.Add(l);
}
Depending on your exact requirements, you may do best with a jagged array of sorts with:
List<string>[] results = new { new List<string>(), new List<string>() };
Or you may do well with a list of lists or some other such construct.
If you want to modify this I'd go with either of the following:
List<string[]> results;
-- or --
List<List<string>> results;
depending on your needs...