Outputting a C# Object list [closed] - c#

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 8 years ago.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Improve this question
I have
List<dynamic> events = new List<dynamic>();
for (int i = 0; i < 3000; i++)
{
if (i % 2 == 0) //is even
{
var dataStart = new
{
TimeId = startTime.AddSeconds(i),
ValueStart = i
};
}
}
how can I output what is in the List object? I am very new to C# so I have tried
for (int j = 0; j < events.Count; j++)
{
Console.WriteLine(events);
}
but this is not working. Any ideas as to what I need to do to correctly output the values of the object?

First, add created items into the list:
List<dynamic> events = new List<dynamic>();
for (int i = 0; i < 3000; i++)
if (i % 2 == 0) {//is even
events.Add( // <- Do not forget Add
new {
TimeId = startTime.AddSeconds(i),
ValueStart = i }
);
Then print the list out
foreach(var item in events)
if (!Object.ReferenceEquals(null, item))
Console.WriteLine("time: {0} value: {1}", item.TimeId, item.ValueStart);

First of all you need to understand that you're having a List of dynamic type (I don't know what that is, maybe you're local Class file). It is initialized as
List<dynamic> events = new List<dynamic>();
Now, the events would have a list of elements that would be dynamic objects.
When you need to output it, you need to reference it. You need this to do that
for (int j = 0; j < events.Count; j++)
{
Console.WriteLine(events[j].SomeProperty.ToString());
}
This code would get some property of each of the dynamic object inide the events list and then it would write it in the Console.

Two things:
You forgot to add your elements to the list:
DateTime startTime = DateTime.Now;
List<dynamic> events = new List<dynamic>();
for (int i = 0; i < 3000; i++)
{
if (i % 2 == 0) //is even
{
var dataStart = new
{
TimeId = startTime.AddSeconds(i),
ValueStart = i
};
events.Add(dataStart); // <--
}
}
Just use a foreach for writing to the console like this:
foreach (var dataPoint in events)
{
Console.WriteLine(dataPoint);
}
EDIT: Since I lost the race, I may as well present a more interesting way to do this:
(This also has the bonus of being backwards compatible to C# 2, whereas dynamic only exists from C# 4 on.)
public static IEnumerable<object> GetEvents(DateTime startTime)
{
for (int i = 0; i < 3000; i++)
{
if (i % 2 == 0) //is even
{
yield return new
{
TimeId = startTime.AddSeconds(i),
ValueStart = i
};
}
}
}
You would call this like so:
DateTime startTime = DateTime.Now;
foreach (var dataPoint in GetEvents(startTime))
{
Console.WriteLine(dataPoint);
}
More on yield return in this answer by Jon Skeet.

You're nearly there, just need to access the element via index (assuming you have anything in the collection):
for (int j = 0; j < events.Count; j++)
{
Console.WriteLine(events[j].FooProperty);
}

Related

Adding method to delegate changes iteration in "for" loop - C# issue? [duplicate]

This question already has answers here:
How to tell a lambda function to capture a copy instead of a reference in C#?
(4 answers)
Closed 5 years ago.
I've faced some issue with C# code. Adding method to delegate in "for" loop increments "i" by one., so "for(int i = 0, i < x ; i++)" must be change to "for(int i = -1, i < x-1; i++)" to work correctly. Why is that?
Code below throws an IndexOutOfRangeException
string[] names = new string[] { "John", "Madeline", "Jack", "Gabby" };
Action showNameDelegate = null;
for (int i = 0; i < names.Length; i++)
{
showNameDelegate += () => global::System.Console.WriteLine(names[i]);
}
foreach (Action showName in showNameDelegate.GetInvocationList())
{
showName();
}
Right code is (look at iterator "i" which starts from -1 but "names[-1]" does not exist):
string[] names = new string[] { "John", "Madeline", "Jack", "Gabby" };
Action showNameDelegate = null;
for (int i = -1; i < names.Length - 1; i++)
{
showNameDelegate += () => global::System.Console.WriteLine(names[i]);
}
foreach (Action showName in showNameDelegate.GetInvocationList())
{
showName();
}
This answer is correct (by Ed Plunkett):
Each delegate references the variable i. They all reference the variable, so when they execute, they'll get whatever value it has right then. The delegates are executed after the for loop completes. At that point, i is equal to names.Length. Make a local copy of i in the body of the loop -- or use a foreach loop, which automatically fixes this issue.
You should change your code like this;
for (int i = -1; i < names.Length - 1; i++)
{
string name = names[i];
showNameDelegate += () => global::System.Console.WriteLine(name);
}
Or you can try to use foreach.

How to count number of iterations in a for loop C# [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm trying to count loop iterations and show it to the user using a LABEL. Tried many solutions but no luck.
Any suggestions regarding this?
Thanks in advance!
Tried this as well.
for (int x = 0; x < DataGridView.Rows.Count; x++)
{
CountLabel.Text = x.ToString();
}
A for loop has a built in counter - for example:
for(int i=0; i <= maxValue; i++)
{
// do stuff
yourLabel.Text = i.ToString();
yourLabel.Update();
}
Perhaps you are referring to a a foreach loop (foreach(var x in y)).
In that case, you need to add a counter yourself:
var loopCounter = 0;
foreach(var x in y)
{
// do stuff
yourLabel.Text = loopCounter.ToString();
yourLabel.Update();
loopCounter++;
}
Declare the index outside the for loop, so you can access it afterwards.
int i = 0;
for (i = 0 ; i < smsCount ; i++)
{
//Send SMS
}
//You can access i here
If you are using foreach loop
int count = 0;
foreach (SMS sms in SMSlist)
{
//Send SMS
count++;
}
You access both i and count outside the loop. You can even declare them in a global scope, if you need to access them from other methods or classes.
var loopcounter=0;
foreach(var x in y){
loopcounter++;
label.text=loopcounter.toString();
//delay();
}
You should be writing this in a progress Handler or a separate thread. As the speed of the loop is much faster than the label can display the text. Hence if you directly do this without the delay you might not get the effect you want.
OR
You can also use a Progress Bar to display the progress of sending the SMS.
private void button1_Click(object sender, EventArgs e)
{
int i;
progressBar1.Minimum = 0;
progressBar1.Maximum = 200;
for (i = 0; i <= 200; i++)
{
progressBar1.Value = i;
}
}

How to optimize code that changes a value deeply nested in an object graph

Below is a crude for-loop to illustrate what I need to do.
Basically, if there are any 'Variable' objects with property 'Name' containing the text "TCC#", then I want to change the 'Type' property (not the .Net type) to 'VariableType.Text'.
The code is going to run over 4800 ParsedCard variables and currently takes a stupid amount of time (about 10 minutes) to simply iterate through the list and write a line to the Debug console.
ParsedCard has
IEnumerable functions which have
IEnumerable groups which have
ParseResults which have
IEnumerable variables
This is such a simple problem but I've tried all sorts of variations using LINQ but can't find anything that performs well (less than 10 seconds).
private void AdjustTCCVariables(IList<ParsedCard> parsedCards)
{
for (var i = 0; i < parsedCards.Count; i++)
{
var parsedCard = parsedCards[i];
for (var j = 0; j < parsedCard.Functions.Count(); j++)
{
var function = parsedCard.Functions.ToList()[j];
for (var k = 0; k < function.Groups.Count(); k++)
{
var group = function.Groups.ToList()[k];
for (var l = 0; l < group.ParseResult.Variables.Count(); l++)
{
var variable = group.ParseResult.Variables.ToList()[l];
if (variable.Name.Contains("TCC#"))
{
//variable.Type = VariableType.Text;
Debug.WriteLine($"Need to change variable at [{i}][{j}][{k}][{l}]");
}
}
}
}
}
}
I've tried with this LINQ but it doesn't actually change the 'variable.Type' of the input list (I suspect because it creates a new copy of the objects in memory and the assignment isn't actually affected the 'parsedCards' IEnumerable at all:
private void AdjustTCCVariables(IEnumerable<ParsedCard> parsedCards)
{
var targetVariables =
parsedCards.SelectMany(x => x.Functions.SelectMany(z => z.Groups))
.SelectMany(x => x.ParseResult.Variables.Where(v => v.Name.Contains("TCC#")));
;
foreach (var variable in targetVariables)
{
variable.Type = VariableType.Text;
}
}
As mentioned, the bottleneck in your iterations is the .ToList() calls.
Since you mention that you only want to edit the variable.Type property, I would solve this like this.
var variables = from parsedCard in parsedCards
from function in parsedCard.Functions
from group in function.Groups
from variable in group.ParseResult.Variables
where variable.Name.Contains("TCC#")
select variable;
foreach (var variable in variables) {
variable.Type = VariableType.Text;
}
You don't need to know anything other than the variable objects that need changing, you don't need all the indexes and all the other variables. Just select what you need to know, and change it.
This way you will not know the indexes, so your Debug.WriteLine(...); line won't work.
Without knowing what the defintion of the classes , here is some tips.
Remove toList, dont count on the iteration (for statement)
int numberOf = parsedCards.Count
for (var i = 0; i < numberOf; i++)
{
//var parsedCard = parsedCards[i];
int noOf2 = parsedCard[i].Functions.Count()
for (var j = 0; j < noOf2; j++)
{
var function = parsedCard[i].Functions[j];
int = function.Groups.Count();
for (var k = 0; k < noOfGroups; k++)
{
var group = function.Groups[k];
int noOfVars = group.ParseResult.Variables.Count();
for (var l = 0; l < noOfVars; l++)
{
var variable = group.ParseResult.Variables[l];
if (variable.Name.Contains("TCC#"))
{
//variable.Type = VariableType.Text;
Debug.WriteLine($"Need to change variable at [{i}][{j}][{k}][{l}]");
}
}
}
}
}

Dictionary Sort .NET 2.0 [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I'm having a problem how to proper sort a dictonary in .NET 2.0. This bit of code is kinda old (2002 or something) and it works, but not the way I want to. Because the AvailableFlights Dictionary can be very huge, this sort function can take a lot of time which clients don't have sooo.
Anyone have an idea how to do this, the only way I know is to add an orderby or something, since I was playing in the garden when it was 2002.
Note: this is code of an ongoing website, the problem is, my boss want this faster but I can't do huge changes to the project.
The sort function itself works like this: There's a dictionary AvailableFlight which contains Flight objects (with the TotalPrice). This comes from an external source so pre-filtering isn't an option. The goal to achieve is to have the flights with the lowest TotalPrice on top.
FOR THE PEOPLE who have no clue what i'm asking, in my project there is a dictionary who contains flight objects stored as object with corresponding integer keys. A flight object has a property Totalprice which need to be sorted ASC. This happens with the code I provide, only the time processing this piece of code takes about 30 seconds or more, which is unacceptable. So the question is, how can I improve this so the time processing cuts down.
public void SortFlightResult()
{
//bool to check sorting is done or not
bool blSort = true;
//bool to stay in while or not
bool blWhileSort = true;
while (blWhileSort)
{
//check the availableFlights
foreach (int i in AvailableFlights.Keys)
{
foreach (int j in AvailableFlights.Keys)
{
//if id j is greater then id i and price is less then j must be in place of i
if ((AvailableFlights[j].TotalPrice < AvailableFlights[i].TotalPrice) && (j > i))
{
//set temperary AvailableFlight object
AvailableFlight avTemp = new AvailableFlight();
avTemp = AvailableFlights[i];
AvailableFlights[i] = AvailableFlights[j];
//keep id of the i (if j.id = 3 and i.id = 2) replace i with j but let id = 2
AvailableFlights[i].ID = i;
AvailableFlights[j] = avTemp;
AvailableFlights[j].ID = j;
//set bool fase so we know sort is not done
blSort = false;
//end both foreach loop so we can start over from the top of availableFlights
goto endLoop;
}
}
}
endLoop:
//if true --> availableFlights is sorted set bool while false to quit the function
if (blSort)
{
blWhileSort = false;
}
else
{//set bool sort back to true
blSort = true;
}
}
}
All the bullsh*t aside, thanks to #D Stanley for his usefull comment.
I Changed to algorithm to a Heap sort and the time processing the sort cuts down from about 30 seconds to 400 miliseconds, really glad with that!
For the people who are interested in the heap sort code:
Heapsort
public void HeapSort()
{
Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();
//Build Max-Heap
Dictionary<int, AvailableFlight> input = AvailableFlights;
int heapSize = input.Keys.Count;
for (int p = (heapSize -1) /2; p >= 0; p--)
{
MaxHeapify(AvailableFlights, heapSize, p);
}
for (int i = AvailableFlights.Count - 1; i > 0; i--)
{
//Swap
AvailableFlight temp = input[i];
input[i] = input[0];
input[0] = temp;
heapSize--;
MaxHeapify(AvailableFlights, heapSize, 0);
}
watch.Stop();
Debug.WriteLine("SortFlightResult 2: " + watch.ElapsedMilliseconds);
}
MaxHeapify
private static void MaxHeapify(Dictionary<int, AvailableFlight> input, int heapSize, int index)
{
int left = (index + 1) * 2 - 1;
int right = (index + 1) * 2;
int largest = 0;
if (left < heapSize && input[left].TotalPrice > input[index].TotalPrice)
{
largest = left;
}
else
{
largest = index;
}
if (right < heapSize && input[right].TotalPrice > input[largest].TotalPrice)
{
largest = right;
}
if (largest != index)
{
AvailableFlight temp = input[index];
input[index] = input[largest];
input[largest] = temp;
MaxHeapify(input, heapSize, largest);
}
}
Assuming you have something like this AvailableFlight class:
public class AvailableFlight
{
public decimal TotalPrice { get; set; }
// ... more properties
}
You can create a class implementing IComparer<AvailableFlight> like this:
public class FlightByPriceComparer : IComparer<AvailableFlight>
{
public int Compare(AvailableFlight x, AvailableFlight y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null) ? 0 : -1;
if (ReferenceEquals(y, null)) return 1;
return x.TotalPrice.CompareTo(y.TotalPrice);
}
}
And use this to sort a List<AvailableFlight> of your dictionary's values:
Dictionary<int, AvailableFlight> AvailableFlights = ... // whereever you got them from
List<AvailableFlight> sortedFlights = new List<AvailableFlight>(AvailableFlights.Values);
sortedFlights.Sort(new FlightByPriceComparer());
This should be faster than your bubble sort, according to documentation it uses these sort algorithms:
This method uses System.Array.Sort, which uses the QuickSort algorithm. This implementation performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.
On average, this method is an O(n log n) operation, where n is Count; in the worst case it is an O(n ^ 2) operation.
Note that it's not possible to sort a dictionary by its values, there is a SortedDictionary but that is only sorted by its Keys.
Use System.Linq to make it easy and clear for reading:
AvailableFlights = AvailableFlights.OrderBy(x => x.Value.TotalPrice).ToDictionary(x => x.Key, x=>x.Value);

Get n unique objects out out M collection

I would like to know how to achieve this task in C#. For example;
I got 10 questions from which 3 is to be displayed to user for them to
type the answer. How can i make the program generate 3 questions that
are non-repeating(unique) assuming the 10 questions that we are
starting with is unique.
I am using the logic in a asp.net application, and the same set of questions are allowed to be displayed the next time page is refreshed, so that's no problem for me.
Use a List for your Question instances, and select one at random (by index). Then remove it from the List and repeat. Something like so;
static void Main(string[] args)
{
List<string> questions = new List<string>();
for (int i = 0; i < 10; i++)
questions.Add("Question " + i);
Random r = new Random();
for (int i = 0; i < 3; i++)
{
int nextQuestion = r.Next(0, questions.Count);
Console.WriteLine(questions[nextQuestion]);
questions.RemoveAt(nextQuestion);
}
}
One of approaches is to shuffle elements randomly and then pick first three of them.
For how to shuffle in C# - Randomize a List<T>.
This approach is better than remove questions from list for big collection because, in the worst case(when randomizing is determined or just happenned badly) it can grow up to O(n^2) due to O(n) complexity of removing.
class Questions
{
const int NUMBER_OF_QUESTIONS = 10;
readonly List<string> questionsList;
private bool[] avoidQuestions; // this is the "do-not-ask-question" list
public Questions()
{
avoidQuestions = new bool[NUMBER_OF_QUESTIONS];
questionsList = new List<string>
{
"question1",
"question2",
"question3",
"question4",
"question5",
"question6",
"question7",
"question8",
"question9"
};
}
public string GetQuestion()
{
Random rnd = new Random();
int randomVal;
// get a new question if this question is on the "do not ask question" list
do
{
randomVal = rnd.Next(0, NUMBER_OF_QUESTIONS -1);
} while (avoidQuestions[randomVal]);
// do not allow this question to be selected again
avoidQuestions[randomVal] = true;
// do not allow question before this one to be selected
if (randomVal != 0)
{
avoidQuestions[randomVal - 1] = true;
}
// do not allow question after this one to be selected
if (randomVal != NUMBER_OF_QUESTIONS - 1)
{
avoidQuestions[randomVal + 1] = true;
}
return questionsList[randomVal];
}
}
Just create Questions object and call questions.GetQuestions() three times

Categories