Bind a linkedlist to a datagridview - c#

I'm trying to bind a linkedlist to a datagridview. The method below works for the properties in the class except the array.
If I declare the array as a new instance the linkedlist is created correctly, but the array is not bound into the datagridview.
If the array is created as a property (I think the code is correct) causes An unhandled exception of type 'System.StackOverflowException' occurred when the linkedlist is created.
Thanks for any help.
public class PayoffNode
{
public int DealNo { get; set; }
public string Category { get; set; }
public string Strategy { get; set; }
public string GreekType { get; set; }
// declare array as instance or as a property?
//public double[] Data = new double[22];
public double[] Data
{
get { return Data; }
set { Data = value; }
}
}
LinkedList<Globals.PayoffNode> PayLL = new LinkedList<Globals.PayoffNode>();
Random Rnd = new Random();
for (int K = 1; K <= 10; K++)
{
var T = new Globals.PayoffNode();
T.Category = "Account==" + K;
T.GreekType = "Greek==" + K;
T.DealNo = K;
T.Strategy = "Strategy==" + K;
for (int DP = 1; DP <= 21; DP++)
{
T.Data[DP] = Rnd.Next(10, 99);
}
PayLL.AddLast(T);
}
List<Globals.PayoffNode> qP = (from P in PayLL
where P.Category == "Account==4" && P.DealNo == 4 && P.GreekType == "Greek==4" && P.Strategy == "Strategy==4"
select P).ToList();
PayoffTable.DataSource = qP;
Update:
Thanks for the comments, this seems to be working.
public class PayoffNode
{
public int DealNo { get; set; }
public string Category { get; set; }
public string Strategy { get; set; }
public string GreekType { get; set; }
public double Data1 { get; set; }
public double Data2 { get; set; }
public double Data3 { get; set; }
public double[] Data = new double[22];
}
LinkedList<Globals.PayoffNode> PayLL = new LinkedList<Globals.PayoffNode>();
Random Rnd = new Random();
for (int K = 1; K <= 10; K++)
{
var T = new Globals.PayoffNode();
T.Category = "Account==" + K;
T.GreekType = "Greek==" + K;
T.DealNo = K;
T.Strategy = "Strategy==" + K;
for (int DP = 1; DP <= 21; DP++)
{
T.Data[DP] = Rnd.Next(10, 99);
}
PayLL.AddLast(T);
}
List<Globals.PayoffNode> qP = (from P in PayLL
where P.Category == "Account==4" && P.DealNo == 4 && P.GreekType == "Greek==4" && P.Strategy == "Strategy==4"
select new Globals.PayoffNode()
{
Category=P.Category,
DealNo=P.DealNo,
GreekType=P.GreekType,
Strategy=P.Strategy,
Data1=P.Data[1],
Data2 = P.Data[2],
Data3 = P.Data[3],
}).ToList();
PayoffTable.DataSource = qP;

One way to avoid making 21 Data properties is to convert the List to DataTable:
class PayoffNode
{
public int DealNo;
public string Category;
public double[] Data; // = new double[21];
}
and then
Random Rnd = new Random();
List<PayoffNode> PayLL = Enumerable.Range(1, 10).Select(i => new PayoffNode {
DealNo = i,
Category = "Account==" + i,
Data = Enumerable.Range(1, 21).Select(d => (double)Rnd.Next(10, 99)).ToArray()
}).ToList();
// List<PayoffNode> to DataTable
var dt = new DataTable();
dt.Columns.Add("DealNo", typeof(int));
dt.Columns.Add("Category"); // typeof(string) by default
for (int i = 1; i <= 21; i++)
dt.Columns.Add("Data" + i, typeof(double));
foreach (var P in PayLL)
{
var dr = dt.Rows.Add(P.DealNo, P.Category);
for (int i = 0; i < 21; i++)
dr[i+2] = P.Data[i]; // +2 is the number of fields before the Data fields
}
PayoffTable.DataSource = dt;
dt.DefaultView.RowFilter = " Category = 'Account==4' ";
The advantage is that you set the DataSource only once and just change the RowFilter to filter it. Also, any changes made in the DataGridView change the DataTable and vice-versa.
Note that arrays in C# and most other languages start from 0 and not from 1 ( .Data[0] to access the first item in the array ), so the for loop to access the Data array in my example is from 0 to 20.

public double[] Data
{
get { return Data; }
set { Data = value; }
}
This is the problem, the object in the set and get method needs to refer to a different object otherwise whenever the object value is set or trying to be retrieved it will just keep calling these methods infinitely. should be...
private double[] _data;
public double[] Data
{
get { return _data; }
set { _data = value; }
}
or...
public double[] Data { get; set; }

Related

For loop takes the the max count

private List<SurveyDetail> GetSurveyDetails()
{
List<SurveyDetail> surveyDetails = new List<SurveyDetail>();
SurveyDetail detail = new SurveyDetail();
int cid = 0;
for (int i = 1; i < 3; i++)
{
detail.choiceId = "1";
detail.choiceDesc = "tesT";
detail.questionId = i.ToString();
surveyDetails.Add(detail);
}
return surveyDetails;
}
public class SurveyDetail
{
public string questionId { get; set; }
public string choiceId { get; set; }
public string choiceDesc { get; set; }
}
when I run the code it question Id always gives me the last number of i that was run for example, in this case, it gives me 2. It gives me 2 on both counts.
Where I want the questionid to be 1 in the first count and 2 in the second.
You should move SurveyDetail initialization into the for body
private List<SurveyDetail> GetSurveyDetails()
{
List<SurveyDetail> surveyDetails = new List<SurveyDetail>();
int cid = 0;
for (int i = 1; i < 3; i++)
{
SurveyDetail detail = new SurveyDetail();//<==NOTE THIS
detail.choiceId = "1";
detail.choiceDesc = "tesT";
detail.questionId = i.ToString();
surveyDetails.Add(detail);
}
return surveyDetails;
}
Incase you want to use : LINQ
var result = Enumerable.Range(1, 3).Select(detail => new SurveyDetail
{
choiceId = "1",
questionId = detail.ToString(),
choiceDesc = "testT",
});

Addition using next object's property value in List

I want to make addition using next object's property value in list.
Here is the sample code.
public class MyClass
{
public List<Model> modelList { get; set; }
public MyClass()
{
modelList = GetModelList();
}
public List<Model> GetModelList()
{
return new List<Model>
{
new Model(){Number = 1, Total = 0},
new Model(){Number = 2, Total = 0},
new Model(){Number = 3, Total = 0},
new Model(){Number = 4, Total = 0},
};
}
}
public class Model
{
public int Number { get; set; }
public int Total { get; set; }
}
In above case :
modelList[0].Total should be modelList[0].Number + modelList[1].Number
What could be the best way to achieve this ? Any help ?
Below is the code How I am achieving currently
for (int i = 0; i < modelList.Count - 1; i++)
{
modelList[i].Total = modelList[i].Number + modelList[i + 1].Number;
}
I added a method ComputeTotal to show a solution
public MyClass()
{
modelList = GetModelList();
modelList = ComputeTotal(modelList);
}
private List<Model> ComputeTotal(List<Model> models)
{
for (var i = 0; i < models.Count; i++)
{
var hasNext = (i + 1) < models.Count;
// no computation if hasNext is false
if (hasNext)
{
var currentNumber = models[i].Number;
var nextNumber = models[i + 1].Number;
models[i].Total = currentNumber + nextNumber;
}
}
return models;
}
i know this is very explicit. But it clearly demonstrates the approach.
Update:
added the hasNext check to avoid System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.

Merging data in a list based on date

I have a generic list which is using this class
public class Data
{
public string Date { get; set; }
public int OkRecords { get; set; }
public int ErrorRecords { get; set; }
}
I also have List<string> which holds unique Dates. I need to add data of original list in such a way that there should be only one record for a date i.e. if there are 10 unique dates then there should be only 10 records filtered out of the original list. I have implemented the following logic but it is taking way too much time if there is more than 100 000 data.
int distinctDatesCount = distinctDates.Count;
for (int i = 0; i < distinctDatesCount; i++)
{
string date = distinctDates[i];
int ok = 0, error = 0;
foreach (var item in dataList.Where(w => w.Date == date))
{
ok += item.OkRecords;
error += item.ErrorRecords;
}
Data dataValues = new Data
{
Date = date,
OkRecords = ok,
ErrorRecords = error
};
DataListCombined.Add(dataValues);
}
DataListCombined is the list in which I am storing the newly merged data.
I've stored the date in string format as I am using it elsewhere where it is required in string format.
You can use Linq GroupBy to group by data by date and then use Sum to add up the counts into single objects.
var DataListCombined = dataList.GroupBy(data => data.Date)
.Select(groupedData =>
new Data {
Date = groupedData.Key,
OkRecords = groupedData.Sum(item => item.OkRecords),
ErrorRecords = groupedData.Sum(item => item.ErrorRecords)
})
.Where(data => distinctDates.Contains(data.Date))
.ToList();
You can also check this resource for more examples.
101 LINQ Samples
Personnally i used a group join. Because record in the DataList shouldn't be in the final result.
public class Data
{
public string Date { get; set; }
public int OkRecords { get; set; }
public int ErrorRecords { get; set; }
}
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
List<string> distinctDates = new List<string>();
for (int i = 0; i < 10000; i++)
{
distinctDates.Add( rand.Next(1, 12) + "/" + rand.Next(1, 30) + "/1");
}
List<Data> dataList = new List<Data>();
for (int i = 0; i < 10000; i++)
{
dataList.Add(new Data{ Date = rand.Next(1,12)+"/"+rand.Next(1, 30)+"/1", OkRecords=0, ErrorRecords=1});
}
Stopwatch watch = new Stopwatch();
watch.Start();
Method1(distinctDates, dataList);
watch.Stop();
Console.WriteLine(watch.Elapsed);
watch.Reset();
watch.Start();
Method2(distinctDates, dataList);
watch.Stop();
Console.WriteLine(watch.Elapsed);
Console.ReadLine();
}
private static void Method1(List<string> distinctDates, List<Data> dataList)
{
List<Data> DataListCombined = new List<Data>();
int distinctDatesCount = distinctDates.Count;
for (int i = 0; i < distinctDatesCount; i++)
{
string date = distinctDates[i];
int ok = 0, error = 0;
foreach (var item in dataList.Where(w => w.Date == date))
{
ok += item.OkRecords;
error += item.ErrorRecords;
}
Data dataValues = new Data
{
Date = date,
OkRecords = ok,
ErrorRecords = error
};
DataListCombined.Add(dataValues);
}
}
private static void Method2(List<string> distinctDates, List<Data> dataList)
{
List<Data> DataListCombined = distinctDates.GroupJoin(
dataList,
distinctDateItem => distinctDateItem,
dataListItem => dataListItem.Date,
(dataListItem, distinctDateItems) => new Data
{
ErrorRecords = distinctDateItems.Sum(item => item.ErrorRecords),
OkRecords = distinctDateItems.Sum(item => item.OkRecords),
Date = dataListItem
}
).ToList();
}
}

list class property in a class c# assign value

class Program
{
static void Main(string[] args)
{
Posting onjPosting = null;
List<Posting> objList = null;
for (int i = 0; i < 100; i++)
{
onjPosting = new Posting();
onjPosting.Key1 = i;
for (int j = 0; j < 5; i++)
{
Choice objChoice = new Choice();
objChoice.ID = i;
objChoice.VAL = j;
onjPosting.GetPostingChoice.Add(objChoice); // GETTING ERROR [ Object reference not set to an instance of an object. ]
}
objList.Add(onjPosting);
}
}
}
public class Choice
{
public int ID { get; set; }
public int VAL { get; set; }
}
public class Posting
{
public int Key1 { get; set; }
public List<Choice> GetPostingChoice { get; set; }
}
While looping through and assigning the value I am getting error . How to solve this ? Please help me out .
My requirement is one parent class (Posting) , can contain number of data List .
Thanks in advance .
You never allocate the GetPostingChoice list so of course it is null.
You could do it in the constructor:
public class Posting
{
public Posting()
{
GetPostingChoice = new List<Choice>();
}
public int Key1 { get; set; }
public List<Choice> GetPostingChoice { get; set; }
}
Add a public constructor on your Posting class:
public class Posting
{
public int Key1 { get; set; }
public List<Choice> GetPostingChoice { get; set; }
public Posting()
{
GetPostingChoice = new List<Choice>();
}
}
You also have other errors:
You do not initialize objList, so you cannot add in there.
List<Posting> objList = null;
So you will get another Null Reference when you get to:
List<Posting> objList = null;
In your second loop you increase i instead of j so it will never end.
for (int j = 0; j < 5; i++)
This is how it should look:
Posting onjPosting = null;
List<Posting> objList = new List<Posting>();
for (int i = 0; i < 1; i++)
{
onjPosting = new Posting();
onjPosting.Key1 = i;
for (int j = 0; j < 5; j++)
{
Choice objChoice = new Choice();
objChoice.ID = i;
objChoice.VAL = j;
onjPosting.GetPostingChoice.Add(objChoice); // GETTING ERROR [ Object reference not set to an instance of an object. ]
}
objList.Add(onjPosting);
}
Since you ask for another approach, and this is just one of the many ways you could do it, have a look at this:
List<Posting> objList = new List<Posting>();
Enumerable.Range(0,100)
.Select
(
(x,i)=>new Posting
{
Key1 = i,
GetPostingChoice = Enumerable.Range(0,5).Select((p,j)=>new Choice{ID = i,VAL = j}).ToList()
}
);

ASP.Net : DataTable convert to JSON with Hierarchy

Hi I'm having a problem in converting my dataTable to JSON format but i cannot get the output that i want.
Here is the example of the datatable
Parent Child
P1 c1
P1 c2
P1 c3
P2 c4
the output that I need is:
[{
Parent:P1,
Child:[
{c1},
{c2},
{c3}
]
},
{
Parent:P2
Child:[{c4}]
}]
But the Output that i always get is:
[{Parent:P1, Child:c1}, {Parent:P1, Child:c2}, {Parent:P1, Child:c3}, {Parent:P2,
Child:c4}]
Use this following code to get your desired result.
public class ParentNode
{
public ParentNode()
{
this.Child = new List<ChildNode>();
}
public string Parent { get; set; }
public List<ChildNode> Child { get; set; }
}
public class ChildNode
{
public string Child { get; set; }
}
class DataTableTOJSON
{
public static string GetJSON(DataTable dt)
{
List<ParentNode> parent = new List<ParentNode>();
for (int i = 0; i < dt.Rows.Count; i++)
{
var innerRow = dt.Rows[i]["Parent"];
var objParent = new ParentNode();
bool alreadyExists = parent.Any(x => x.Parent.Contains(innerRow.ToString()));
if (alreadyExists)
continue;
DataRow[] foundRows = dt.Select("[Parent]='" + innerRow + "'");
for (int k = 0; k < foundRows.Count(); k++)
{
var objChild = new ChildNode();
objChild.Child = foundRows[k]["Child"].ToString();
objParent.Child.Add(objChild);
}
objParent.Parent = innerRow.ToString();
parent.Add(objParent);
}
JavaScriptSerializer jsonString = new JavaScriptSerializer();
return jsonString.Serialize(parent);
}
}
Your will get the following output.
[{"Parent":"P1","Child":[{"Child":"c1"},{"Child":"c2"},{"Child":"c3"}]},{"Parent":"P2","Child":[{"Child":"c4"}]}]
I hope this will help you.

Categories