What's a good collection in C# to store the data below:
I have check boxes that bring in a subjectId, varnumber, varname, and title associated with each checkbox.
I need a collection that can be any size, something like ArrayList maybe with maybe:
list[i][subjectid] = x;
list[i][varnumber] = x;
list[i][varname] = x;
list[i][title] = x;
Any good ideas?
A List<Mumble> where Mumble is a little helper class that stores the properties.
List<Mumble> list = new List<Mumble>();
...
var foo = new Mumble(subjectid);
foo.varnumber = bar;
...
list.Add(foo);
,..
list[i].varname = "something else";
public Class MyFields
{
public int SubjectID { get; set; }
public int VarNumber { get; set; }
public string VarName { get; set; }
public string Title { get; set; }
}
var myList = new List<MyFields>();
To access a member:
var myVarName = myList[i].VarName;
A generic list, List<YourClass> would be great - where YourClass has properties of subjectid, varnumber etc.
You'd likely want to use a two-dimensional array for this, and allocate positions in the second dimension of the array for each of your values. For instance, list[i][0] would be the subjectid, list[i][1] would be varnumber, and so on.
Determining what collection, typically begins with what do you want to do with it?
If your only criteria is it can be anysize, then I would consider List<>
Since this is a Key, Value pair I would recommend you use a generic IDictionary based collection.
// Create a new dictionary of strings, with string keys,
// and access it through the IDictionary generic interface.
IDictionary<string, string> openWith =
new Dictionary<string, string>();
// Add some elements to the dictionary. There are no
// duplicate keys, but some of the values are duplicates.
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
As others have said, it looks like you'd be better creating a class to hold the values so that your list returns an object that contains all the data you need. While two-dimensional arrays can be useful, this doesn't look like one of those situations.
For more information about a better solution and why a two-dimensional array/list in this instance isn't a good idea you might want to read: Create a list of objects instead of many lists of values
If there's an outside chance that the order of [i] is not in a predictable order, or possibly has gaps, but you need to use it as a key:
public class Thing
{
int SubjectID { get; set; }
int VarNumber { get; set; }
string VarName { get; set; }
string Title { get; set; }
}
Dictionary<int, Thing> things = new Dictionary<int, Thing>();
dict.Add(i, thing);
Then to find a Thing:
var myThing = things[i];
Related
After an extensive search, I ask here: is there a way to "apply" a hashtable to object properties? For example, if I have a class:
public class MyClass
{
public string PropertyOne {get;set;}
public int PropertyTwo {get;set;}
}
Now, if I have a Hashtable of:
var table = new Hashtable {
{ "PropertyOne", "My string"},
{ "PropertyTwo", 4 }
};
Can I plug the table into an instance of the class so that Object.PropertyOne becomes "My string", etc, without having to parse it myself?
What you are referring to is often referred to as a mixture between "auto-conversion" and "de-serialization". In this specific case it is most easily achieved via non-recursive reflection.
MyClass mine = new MyClass();
table.Cast<DictionaryEntry>()
.ToList()
.ForEach((entry) => {
var field = mine.GetType().getProperty((string)entry.Key);
field.SetValue(mine, entry.Value);
});
I have a list of string array and I would like to make both collection read-only.
So I have this code:
public XmlPatternTree(IList<string> nodeNames, IList<IList<string>> attributeNames,
IList<IList<string>> attributeValues) : this()
{
NodeNames = new ReadOnlyCollection<string>(nodeNames);
AttributeNames = new ReadOnlyCollection<ReadOnlyCollection<string>>();
AttributeValues = attributeValues;
Depth = NodeNames.Count;
}
My issue is that AttributeNames and AttributeValues assignments causes a compilation error, it seems that I can create a ReadonlyCollection of ReadonlyCollection from a non-readonly collection of non-readonly objects.
Is there something I can do other than looping over all the values and add them in the list ?
Thanks
If you change your type from IList<string> to just List<string>, then this should work:
attributeNames.Select((x) => x.AsReadOnly()).ToList().AsReadOnly();
If you can't modify your method signature (i.e. you have to keep IList<string>), then you can do this:
attributeNames.Select((x) => x.ToList().AsReadOnly()).ToList().AsReadOnly();
If the version of the .net framework is greater then 4.0 the generic version of List<> implements the IReadOnlyCollection<> interface.
If it is more convenient for you, you can change your signature from IList<ILIst<>> to List<List<>> and should work fine.
AttributeNames = attributeNames;
AttributeValues = attributeValues;
Just a note on the covariance of the IReadOnlyList<out T> type (similar to vasil oreshenski's answer).
If you decide to have:
public XmlPatternTree(IReadOnlyList<string> nodeNames,
IReadOnlyList<IReadOnlyList<string>> attributeNames,
IReadOnlyList<IReadOnlyList<string>> attributeValues) : this()
{
NodeNames = nodeNames;
AttributeNames = attributeNames;
AttributeValues = attributeValues;
}
public IReadOnlyList<string> NodeNames { get; private set; }
public IReadOnlyList<IReadOnlyList<string>> AttributeNames { get; private set; }
public IReadOnlyList<IReadOnlyList<string>> AttributeValues { get; private set; }
public int Depth => NodeNames.Count;
in your class, then the covariance mentioned means you can use reference conversions, and not any wrapping inside another class, as in:
var nn = new List<string>();
var an = new List<string[]>();
var av = new List<string[]>();
// populate 'nn', 'an', and 'av'
// the following compiles with no wrapper class:
var tree = new XmlPatternTree(nn, an, av);
Of course, people can cast the interfaces back to the actual types, like List<string[]>, and modify the collections without using reflection, if they guess that the type is really that list of arrays. However, that would be quite malignant, so you could assume it is no problem if only "good" people use your class
PS! What I said and coded above with IReadOnlyList<out T> could just as well have been done with IReadOnlyCollection<out T> since it is covariant ("out") as well. You would just not have the indexer access on the properties (such as var name = tree.AttrbuteNames[idx1][idx2]). But then you could use HashSet<> and similar which are not IReadOnlyList<>.
I have two List<CustomObject>, called list1 and list2
public class CustomObject
{
public string foo { get; set; }
public string bar{ get; set; }
}
The goal is to generate a new list with all the entries that have been modified/added in list2.
Because these lists can get pretty long, looping through them is not an option ...
Any ideas?
Adding another answer to accomodate some additional NFRs that have come up in the comments:
Objects can be identified by a hash code
The list is very big, so performance is an issue
The idea is to compare an old list to a new list to see if any new hash codes have popped up.
You will want to store your objects in a dictionary:
var list = new Dictionary<string, CustomObject>();
When you add them, provide the hash as the key:
list.Add(customObject.Hash, customObject);
To scan for new ones:
var difference = new List<CustomObject>();
foreach (customObject o in newList)
{
if (oldList.ContainsKey(o.Hash)) difference.Add(o);
}
Log(String.Format("{0} new hashes found.", difference.Count));
By using the Dictionary you take advantage of the way the keys are stored in a hash table. Finding an item in a hash table is faster than just doing a scan & compare sort of thing. I believe this will be O(n*log(n)) instead of O(n^2).
Here's a traditional way to do it:
public class CustomObject : IComparable
{
public string foo { get; set; }
public string bar{ get; set; }
public int CompareTo(CustomObject o)
{
if (this.foo == o.foo && this.bar == o.bar) return 0;
//We have to code for the < and > comparisons too. Could get painful if there are a lot of properties to compare.
if (this.Foo == o.Foo) return (this.Bar.CompareTo(o.Bar));
return this.Foo.CompareTo(o.Foo);
}
}
Then use Linq.Except:
listA.Except(listB)
I'm having a trouble defining a Dictionary for quick accessing Lambda Expressions.
Let's suppose we have a well-known class like this:
class Example
{
public string Thing1;
public DateTime Thing2;
public int Thing3;
}
What a want to do is something like this:
var getters = new Dictionary<string, IDontKnowWhatGoesHere>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);
Is this possible?
Edit:
This is my use case for this object:
List<Example> array = new List<Example>();
// We actually get this variable set by the user
string sortField = "Thing2";
array.Sort(getters[sortField]);
Many thanks for your help.
You've got a couple of options. If, as in your example, the things you want to get are all the same type (i.e. String), you can do
var getters = new Dictionary<string, Func<Example, String>>();
However, if they're different types, you'll need to use the lowest common subclass, which in most cases will be Object:
var getters = new Dictionary<string, Func<Example, object>>();
Note that you'll then need to cast the return value into your expected type.
Try:
var getters = new Dictionary<string, Func<Example, object>>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);
The first generic type parameter of the Func delegate is the type of the input, and the second generic type parameter is the type of the output (use object because you've different output types).
More about Func: Func<T, TResult> Delegate
var getters = new Dictionary<string, Expression<Func<Example, object>>>();
However, string Thing1 should be public.
I really think you are thinking about this in the wrong way. Why use a dictionary at all? If your class definition is correct, then just use a List<Example>.
List<Example> dataList = new List<Example>();
dataList.Add(new Example { Thing1 = "asdf", Thing2 = "qwert", Thing3 = 2 });
Then you can use linq on it.
IEnumerable<Example> sortedByT3 = dataList.OrderBy(x => x.Thing3);
sortedByT3.Last().Thing2 = "hjkl";
You can also use a dynamic order by provided by Marc Gravell's answer:
var sortedByString = dataList.AsQueryable().OrderBy("Thing2");
No need for lambdas, just direct access to the data.
As everyone has said, you need to make the members public. I would suggest you change it to the following:
public class Example
{
public string Thing1 { get; set; }
public string Thing2 { get; set; }
public int Thing3 { get; set; }
}
I've got a group of data that looks like this:
001 001 One
001 002 Two
001 003 Three
002 001 One
002 002 Two
002 003 Three
...
Now, certainly, I could create an array of string[x][y] = z, but this array has to be resizable, and i'd prefer to use the string representations of the indexers than convert to numeric. The reason is that i will need to look up the data by string, and i don't see the point in needless string->number conversions.
My first thought was this:
Dictionary<string, Dictionary<string, string>> data;
data = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> subdata = Dictionary<string, string>();
subdata.Add(key, string);
data.add(key2, subdata);
and this works, but is somewhat cumbersome. It also feels wrong and kludgy and not particularly efficient.
So what's the best way to store this sort of data in a collection?
I also thought of creating my own collection class, but I'd rather not if I don't have to. I'd rather just use the existing tools.
This is pretty common request, and most people end up writing some variation of a Tuple class. If you're using ASP.Net, you can utilize the Triple class that's already available, otherwise, write something like:
public class Tuple<T, T2, T3>
{
public Tuple(T first, T2 second, T3 third)
{
First = first;
Second = second;
Third = third;
}
public T First { get; set; }
public T2 Second { get; set; }
public T3 Third { get; set; }
}
There's a generic three-tuple class, so you can create a new List<Tuple<string, string, string>>() and create your tuples and add them. Expand on that basic class with some indexing functionality and you're up up and away.
Edit: A list with a dictionary doesn't seem like the correct approach, because each dictionary is only holding one value. There is no multi-entry relationship between the key and values - there is simply one multi-part key and one associated value. The data is equivalent to a database row (or tuple!).
Edit2: Here's an indexable list class you could use for convenience.
public class MyTupleList : List<Tuple<string, string, string>>
{
public Tuple<string, string, string> this[string first, string second]
{
get
{
return (this.Find(x => x.First == first && x.Second == second));
}
set
{
this[first, second] = value;
}
}
}
I think this really depends on what you are modelling here. If you're planning to use an object-oriented approach, you shouldn't be thinking of these as arbitrary items inside a data structure.
I'm guessing from looking at this that the first two columns are serving as a "key" for the other items. Define a simple struct, and create a dictionary of like so:
struct Key {
public int Val1 { get; set; }
public int Val2 { get; set; }
}
....
Dictionary<Key, string> values;
Obviously Key and the items inside it should be mapped to something closer to what you are representing.
Given a suitable Pair<A,B> class*, left as an exercise for the reader, you could use a Dictionary<Pair<string, string>, string>.
* A class with equality and hash code overrides, nothing terribly hard.
Would a List<List<T>> work for you? Still kludgy, but better than dictionaries IMHO.
EDIT: What about a Dictionary<string,string> and mapping the two keys to a single string?
var data = new Dictionary<string,string>(StringComparer.Ordinal);
data[GetKey("002", "001")] = "One";
with
string GetKey(string a, string b) {
return a + "\0" + b;
}
List<List<string>> is really your best bet in this case. But I agree, it's kludgy. Personally, I would create a custom class that implements a two-dimensional indexer and maybe use a List<List<T>> internally.
For example:
public class DynamicTwoDimensonalArray<T>
{
private List<List<T>> Items = new List<List<T>>();
public T this[int i1, int i2]
{
get
{
return Items[i1][i2];
}
set
{
Items[i1][i2] = value;
}
}
}
This is a basic idea to get you going; clearly the setter needs to deal with bounds issues. But it's a start.
Edit:
No. As I said, I would prefer to index them by string. And they may not always be sequential (might have a missing number in the middle). - Mystere Man
Hmm... this is interesting. If that's the case, your best bet would be to create some sort of concatenation of the combination of the two indexers and use that as the key in a single-level dictionary. I would still use a custom class to make using the indexing easier. For example:
public class TwoDimensionalDictionary
{
private Dictionary<string, string> Items = new Dictionary<string, string>();
public string this[string i1, string i2]
{
get
{
// insert null checks here
return Items[BuildKey(i1, i2)];
}
set
{
Items[BuildKey(i1, i2)] = value;
}
}
public string BuildKey(string i1, string i2)
{
return "I1: " + i1 + " I2: " + i2;
}
}
If you are ever going to need to find z by given (x,y) (and not, for example, find all y by given x), then use this:
Dictionary<KeyValuePair<string, string>, string>
Otherwise, your dictionary is fine as is.