I am making a program that automates data messaging.
I have an Excel sheet that has a Name column, Type Column, and Value Column.
It looks like this:
Name Type Value
Sam A 32
Ben B 65
Sam B 213
max B 23
max C 24
max C 12
Ben C 45
This data is not real, but it is similar to what I am working with.
Note: some of the names do not have certain types.
I have loaded the data in 3 arrays arrName[], arrType[], and arrValue[]
I wish to make the data look like this with a 3D array arrPro[name, type, value]. All the values of the same type should belong to the same name and all the values should be added up together to form a total value.
Load excel data directly to DataSet is the most simple method.
If you do want a 3D array, I suggest
Tuple<string, string, int> as the data holder for each row.
and
List<Tuple<string, string, int>> will hold all your data.
This structure might hold your data
public class MyTypes
{
public string TypeName;
public List<NamesValues> Names;
}
public class NamesValues
{
public string Name;
public List<int> Values;
}
It's not simplier and cleaner to store your data in some List<YourObject> for example:
public class YourObject {
public string Name { get; set; }
public string Type{ get; set; }
public int Value { get; set; }
}
and then count what you want with linq (more less):
List<YourObject> yourObject = "your logic goes here (with whole data)";
List<YourObject> result = from s in yourObject
group s by new { s.Name, s. Type) into r
select new YourObject { Name = r.Name, Type = r.Type, Value = r.Sum(s => s.Value) };
I'm not shure it's exactly what you're looking for (grouping type).
You should use a Dictionary.
public Enum EType
{
A,
B,
C
}
public class PatientData
{
public EType Type { get; set; }
public int Value {get; set; }
}
public class PatientManager
{
private readonly Dictionary<String, List<PatientData>> _patients = new Dictionary<String, List<PatientData>>();
public void AddPatientData(string name, EType type, int value)
{
var patientData = new PatientData
{
Type = type,
Value = value
};
List<PatientData> patientDatas;
if (!dictionary.TryGetValue(name, out patientDatas))
{
patientDatas = new List<PatientData>();
dictionary.Add(key, patientDatas);
}
_patientDatas.Add(patientData);
}
public void LoadData(string[] names, EType[] types, int[] values)
{
var iMax = Math.Min(names.Length, Math.Min(type.Length, values.Length));
for (var i = 0; i < iMax; i++)
{
AddPatientData(names[i], types[i], values[i]);
}
}
}
Related
Let's say I have an object that represents a field of data, that object needs the following properties: Name, Type, Value, Length. Here is the object:
class Field<T>
{
public string Name { get; set; }
public Type Type
{
get
{
return typeof(T);
}
}
public int Length { get; set; }
public T Value { get; set; }
}
I have used generics, because I want to force the user of the code to only be able to assign a Value of certain Type.
Now the problem is when I want to create a list of fields.
If I create the list like List<Field<object>> then we can assign any Value to a given Field on the list, and when we query for Type, we get 'object'.
The thing is - on that list I might want few fields holding strings, few holding ints, dates, and even custom objects that in turn will have a list of Fields...
Is the Generics a good solution for something like that? If yes, how would I go about implementing it? If not, what is a better way?
---EDIT---
Just to add some more background:
1. I might want a list of fields, and each field will hold different data type, like so :
List<Field<object>> lst = new List<Field<object>>();
lst.Add(new Field<string>());
lst.Add(new Field<int>());
lst.Add(new Field<SomeObjectFromMyApp>());
2. Later on I will have to query these objects, and their attributes automaticaly in a loop, something like that:
foreach(Field<object> fld in lst)
{
Type t = fld.Type;
//do some other stuff
}
Yes, generics is a good choice. The key to achieving type-safety (and being identify the type with the Type property is to add an abstraction between the list and Field<T> class.
Have Field<T> implement the interface IField. This interface doesn't need any members.
Then declare your list as being List<IField>.
That way you constrain the list to only contain fields, but each field can be of a different type.
To then read the values later, just do
foreach(var field in list)
{
var type = field.Type;
....
}
I suggest you to define an interface and Field<T> implements that interface
public interface IField
{
}
public class Field<T> : IField
{
public string Name { get; set; }
public Type Type
{
get
{
return typeof(T);
}
}
public int Length { get; set; }
public T Value { get; set; }
}
so you can write this code:
var list = new List<IField>();
now this list can contain any object of type Field<T>
As a few commenters already mentioned, you cannot access the Type property if you create an empty Interface, so I would rather do:
public interface IField
{
Type Type { get; }
string Name { get; set; }
int Length { get; set; }
}
public class Field<T> : IField
{
public string Name { get; set; }
Type IField.Type => typeof(T);
public int Length { get; set; }
public T Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
Then you can check of which datatype the value property is and cast the object to the right type:
class Program
{
static void Main(string[] args)
{
var fieldList = new List<IField>()
{
new Field<string>()
{
Value = "Hello World!",
Length = 12,
Name = "A string"
},
new Field<int>()
{
Value = 4711,
Length = sizeof(int),
Name = "An integer value"
},
new Field<double>()
{
Value = 2.4,
Length = sizeof(double),
Name = "A double value"
},
};
foreach (var field in fieldList)
{
if (field.Type == typeof(string))
{
PrintField(field, "String value:");
}
else if (field.Type == typeof(int))
{
PrintField(field, "Integer value:");
}
else if (field.Type == typeof(double))
{
PrintField(field, "Double value:");
}
}
}
static void PrintField(IField field, string info)
{
Debug.WriteLine(info);
Debug.WriteLine($"\tName: {field.Name}, Length: {field.Length}, Value: {field}");
}
}
The code produces the following output:
// String value:
// Name: A string, Length: 12, Value: Hello World!
// Integer value:
// Name: An integer value, Length: 4, Value: 4711
// Double value:
// Name: A double value, Length: 8, Value: 2,4
I receive data from an external API as a Deedle dataframe. I need to take this data and convert it to a List of a custom class to be inserted into a database via Entity Framework.
Would anyone be able to point me in the right direction? I've not used Deedle before and am having trouble finding the best way to extract data.
The custom object I need to populate looks like the below:
public class FrameData
{
public string SecurityId { get; set; }
public string FieldName { get; set; }
public DateTime Date { set; get; }
public decimal value { get; set; }
}
Thanks,
Nick
There are many ways to get data from a Deedle frame. Does Entity Framework allow you to use interfaces? If so, then there is a nice function GetRowsAs which lets you do this:
// Given a simple Person interface
public interface Person {
int Age { get; }
string Name{ get; }
}
// And a sample data frame with some data
Frame<int, string> df = Frame.FromValues(new[] {
Tuple.Create(1, "Name", (object) "One"),
Tuple.Create(2, "Name", (object) "Two"),
Tuple.Create(1, "Age", (object) 42),
Tuple.Create(2, "Age", (object) 21)
});
// You can get an array of rows using
var rows = df.GetRowsAs<Person>();
If Entity Framework cannot handle interfaces, then this method sadly won't work. In that case, you'll need something like:
var rows =
df.Rows.Select(row =>
new Person { Name = row.Value.GetAs<string>("Name"),
Age = row.Value.GetAs<int>("Age"))).Observations;
What #Tomas Petricek said is a good example, but having to many diffrent classes, this may become a problem.
So here i made an example how to dynamicly convert it to a specific class, and use attribute to mapp between the property and the index of column.
// Mapp a key to an index
public class IndexAttribute: Attribute(){
public int Index { get; private set; }
public IndexAttribute(int index){
Index = index;
}
}
public class FrameData
{
[IndexAttribute(0)]
public string SecurityId { get; set; }
[IndexAttribute(3)]
public string FieldName { get; set; }
[IndexAttribute(2)]
public DateTime Date { set; get; }
[IndexAttribute(1)]
public decimal value { get; set; }
}
// create a class the convert the frame to class
public static List<T> Convert<T>(this DataTable data) where T: class
{
var list = new List<T>();
foreach(var row in data.Rows){
object item = Activator.CreateInstance(typeof(T));
var props = typeof(T).GetProperties();
foreach(var p in props){
var index = p.GetCustomAttribute<IndexAttribute>()?.Index ?? -1;
if (index< 0)
continue;
if (table.Columns.length > index) // if the index exist
{
var value = row[index]; // get the value.
if (value == null)
continue; // ignore null value
if (prop.PropertyType == typeof(string))
prop.SetValue(item, value.ToString());
if (prop.PropertyType == typeof(DateTime))
prop.SetValue(item, DateTime.Parse(value.ToString()));
// .. now check for decimal, int etc
}
}
list.Add(item);
}
return list;
}
And now all you need is to call the function
List<Person> persons = df.Convert<Person>(); // that all
I need a clear example that shows me how to define a list that has n rows and 4 columns and how to use it. I need a list to save my data like the below image. as you see this could be a dictionary.
You need to create a class with all the above properties
public class Sample
{
public string vocabulary { get; set; }
public string meaning { get; set; }
public int number { get; set; }
public int group { get; set; }
}
and then you can create a List of type Sample,
List<Sample> yourList = new List<Sample>();
You can add items to the list as below
yourList.Add(new Sample { vocabulary = "massive", meaning = "very big", number = 5, group = 15 });
You can access them later like this, if you want the first element,
var result = yourList[0];
this is the easiest and best way of doing it. You need to create a new class and then create new instances of the class and then add it to the list and then use LINQ to get the data out
void Main()
{
var list = new List<myClass>()
list.Add(new myClass() {
Vocabluary = "Vocabluary ",
Meaning = "meaning",
Number = 1,
Group = 2})
}
public class myClass
{
public string Vocabluary { get; set; }
public string Meaning { get; set; }
public int Number { get; set; }
public int Group { get; set; }
}
yes... as Sajeetharan mentioned, with a custom class you can create an any dimensions List. but i don't think you need to think about dimension in C#... it is a bit more high level than that.
just simply create a class and put everything you need in it...
public class CustomClass{
public string d1;
public int d2;
public string d3;
public string d4;
...
//you can easily create a N dimension class
}
to access it and apply it
public void Main(){
List<CustomClass> list = new List<CustomClass>();
CustomClass cc = new CustomClass();
cc.d1 = "v1";
cc.d2 = 0; //v2
list.Add(cc);
//to access it
foreach(CustomClass tmpClass in list)
{
string d1Value = tmpClass.d1;
int d2Value = tmpClass.d2;
}
}
I have some different data types that i need to do something with in a function. Those data needs to be processed in the function and returned as an object i believe it is called.
This is some not tested code i just wrote here, but i think it displays what im trying to do .. I hope you guys can help me out how to do it.
private void Button_Click(object sender, RoutedEventArgs e)
{
// Here im calling the function which returns data to the object
object thoseProcessedData = SomeTestObject(5, "ABC", SomeOtherThing);
// When returned i want to be able to use the different data like so.
string useItLikeThis = thoseProcessedData.newString;
int numbersLikeThis = thoseProcessedData.newNumber;
}
public object SomeTestObject(int numbers, string letters, AnotherType anothertype)
{
string newString = letters.Substring(0,5);
int newNumber = numbers + 10;
AnotherType newType = anothertype.Something();
return processedData;
}
Please guys dont kill me, if this is a too stupid question. Im still very new to C# ..
If you dont get what im trying to do, please ask! Since my english is not the best i thought this way would be the best to show you what i want..
Create class which holds data you want to pass and return:
public class Data
{
public string Letters { get; set; }
public int Number { get; set; }
public AnotherType Thing { get; set; }
}
Pass it to method:
var data = new Data { Letters = "ABC", Number = 5, Thing = SomeOtherThing };
DoSomething(data);
// here data will have modified values
Thus class is a reference type, all changes to its members inside DoSomething method, will be reflected in your data object reference. So, changes can look like:
public void DoSomething(Data data)
{
data.Letters = data.Letters.Substring(0,5);
data.Number += 10;
data.Thing.Something();
}
Well, you are on the right track (apart from the use of the object keyword/class)!
The object class is the base class of every reference type in C#, it has 3 or 4 functions, and no properties. You will very rarely directly use this class.
The simplest method to do what are you trying to accomplish what you want is to use a Tuple.
This would look like:
public Tuple<string, int, AnotherType> SomeTestObject(
int numbers, string letters, AnotherType anothertype)
{
string newString = letters.Substring(0,5);
int newNumber = numbers + 10;
AnotherType newType = anothertype.Something();
return Tuple.Create(newString, newNumber, newType);
}
If, however, this is going to be used in other places, passed around, etc. you should create a separate object, populate it, and return it.
public MyDataClass SomeTestObject(
int numbers, string letters, AnotherType anothertype)
{
string newString = letters.Substring(0,5);
int newNumber = numbers + 10;
AnotherType newType = anothertype.Something();
return new MyDataClass(newString, newNumber, newType);
}
//Somewhere else, probably another file
public class MyDataClass
{
public string StringData {get; set;}
public int NumberData {get; set;}
public AnotherType ObjectData {get; set;}
public MyDataClass(string myString, int, myNumber, AnotherType myObject)
{
StringData = myString;
NumberData = myNumber;
ObjectData = myObject;
}
}
MSDN For:
Tuple
Object
Create a class to represent that data:
public class ProcessedData
{
public string NewString {get; set;}
public int NewNumber {get; set;}
public AnotherType NewType {get; set;}
}
then populate an instance of that class and return it:
private void Button_Click(object sender, RoutedEventArgs e)
{
// Here im calling the function which returns data to the object
ProcessedData thoseProcessedData = SomeTestObject(5, "ABC", SomeOtherThing);
// now you can access those properties
string useItLikeThis = thoseProcessedData.NewString;
int numbersLikeThis = thoseProcessedData.NewNumber;
}
public ProcessedData SomeTestObject(int numbers, string letters, AnotherType anothertype)
{
ProcessedData processedData = new ProcessedData();
processedData.newString = letters.Substring(0,5);
processedData.newNumber = numbers + 10;
processedData.newType = anothertype.Something();
return processedData;
}
There are mechanisms (anonymous types, dynamic) that would make it possible to dynamically "find" properties at run-time, but defining a class and statically typing the return type is by far safer.
Firstly, your English is fine. Don't worry about that :)
Secondly, what you want to do is just create a class that has those properties on it.
class YourClass {
public string NewString { get; set; }
public int NewNumber { get; set; }
}
Then return an instance of this out of your method:
return new YourClass() {
NewString = letters.Substring(0, 5),
NewNumber = numbers + 10
};
For this you can create a simple class.
public class Data
{
public string NewString { get; set; }
public int NewNumber { get; set; }
}
Then you can return it from a method.
Data ReadData()
{
return new Data {
NewString = CalculateNewString(),
NewNumber = CalclulateNewNumber()
};
}
When you need to return more than one value, you need to create your own class. A class (among other things) encapsulates or "packages together" one or more pieces of data. Here is an example:
public class MyCustomClass {
public int MyCustomInt { get; set; }
public string MyCustomString { get; set; }
public bool MyCustomYesNo { get; set; }
}
This class contains three properties. Properties contain data that can be read from (get) or written to (set). You can now write a function that returns an instance of this property:
public MyCustomClass MyFunction()
{
return new MyCustomClass() {
MyCustomInt = 15, MyCustomString = "Hello World!",
MyCustomYesNo = true
};
}
This function will create a new instance of our MyCustomClass and fill each property with values. And now you can call it like this:
MyCustomClass myVar = MyFunction();
int myInt = myVar.MyCustomInt; // Contains 15
string myString = myVar.MyCustomString; // Contains "Hello World!"
bool myYesNo = myVar.MyCustomYesNo; // Contains true
Now of course, your function can do anything it wishes. I was just providing an example.
Hope this makes sense!
All, I want to create an object array foo[], where the constructor for Foo is
public Foo(string name, string discription){}
I have a database object which has a structure (not incuding stored procedures, functions or views for simplicity) like
public class Database
{
public string name { get; set; }
public string filename { get; set; }
public List<Table> tables { get; set; }
public Database(string name, string filename)
{
this.name = name;
this.filename = filename;
}
}
protected internal class Table
{
public string name { get; set; }
public List<Column> columns { get; set;}
public Table(string name, List<Column> columns)
{
this.name = name;
this.columns = columns;
}
}
protected internal class Column
{
public string name { get; set; }
public string type { get; set; }
public Column(string name, string type, int maxLength,
bool isNullable)
{
this.name = name;
this.type = type;
}
}
I would like to know the quickest way to add Column and Table information to the Foo[] object array?
Clearly I can do
List<Foo> fooList = new List<Foo>();
foreach (Table t in database.tables)
{
fooList.Add(new Foo(t.Name, "Some Description"));
foreach (Column c in t.columns)
fooList.Add(new Foo(c.Name, "Some Description"));
}
Foo[] fooArr = fooList.ToArray<Foo>();
But is there a quicker way? Clearly LINQ is likely to be slower for a query that does a simalar operation, but I care allot about speed here so any advice would be appreciated. Perhaps the use of a HashSet would be the way to go as there will not be duplicate entries...
Thanks for your time.
I would say change your foreach loop to for loop, as discussed here In .NET, which loop runs faster, 'for' or 'foreach'?
Datastructure wise, you do need mutable structure, unless you know exactly how many records you will be inserting into fooList, then you can use Array instead of list. According to the answer of the foreach vs for-loop question, assuming it's correct, for loops on List are a bit more than 2 times cheaper than foreach loops on List, and Looping on array is around 2 times cheaper than looping on List.
So 2 improvement would be:
change foreach to for
use linq to compute the length for the array
as per #Tim Schmelter, and change List to Array
You could initialize the array with the correct size and only use it without a backing list:
int size = db.tables.Sum(t => t.columns.Count + 1);
Foo[] fooArr = new Foo[size];
int currentSize = 0;
foreach (var tbl in db.tables)
{
fooArr[currentSize++] = new Foo(tbl.Name, "Some Discription");
foreach(var c in tbl.columns)
fooArr[currentSize++] = new Foo(c.Name, "Some Discription");
}