I have a time sensitive application where I get the rank of each object and work out who won or tied for first. With my current algorithm I get some lag in my program so am hoping to speed it up. In this demo version I just get a random number for the ranks as the real rank calc requires too much code to post.
Can anybody suggest how I might do this more quickly as the Update method can get called tens of thousands of times for a single run?
class Program
{
static int runOuts = 0;
static Dictionary<RankedObject, int> dictionaryWins = new Dictionary<RankedObject, int>();
static Dictionary<RankedObject, int> dictionaryDraws = new Dictionary<RankedObject, int>();
static Random random = new Random();
static List<RankedObject> rankedObjects = new List<RankedObject>();
static void Main(string[] args)
{
// create some objects for demo
rankedObjects.Add(new RankedObject());
rankedObjects.Add(new RankedObject());
rankedObjects.Add(new RankedObject());
// add each object to the win/draw dictionaries so we can count wins/draws for each
foreach (RankedObject rankedObj in rankedObjects)
{
dictionaryWins.Add(rankedObj, 0);
dictionaryDraws.Add(rankedObj, 0);
}
// calculate wins/draws many times
for (int i = 0; i < 10000; i++)
{
Update();
}
// set equity results in each ranked combo and print results
foreach (RankedObject rankedCombo in rankedObjects)
{
rankedCombo.WinEquity = dictionaryWins[rankedCombo] / (double)runOuts;
rankedCombo.DrawEquity = dictionaryDraws[rankedCombo] / (double)runOuts;
Console.WriteLine(rankedCombo);
}
}
private static void Update()
{
// keep a list of ranks for each object so we can get max/winning value easily
List<int> ranks = new List<int>();
// get a rank for each object
foreach (RankedObject rankedCombo in rankedObjects)
{
int rank = random.Next(3);
ranks.Add(rank);
rankedCombo.Rank = rank;
}
// get the maximum rank and how many times it occurs, so we know if their is a tie for the win
int max = ranks.Max();
int maxOccurences = 0;
foreach (int i in ranks)
{
if (i == max)
{
maxOccurences++;
}
}
// loop over each object to record if the object won or tied for win
foreach (RankedObject rankedObj in rankedObjects)
{
if (rankedObj.Rank == max && maxOccurences == 1) // current rankedObj was winner
{
dictionaryWins[rankedObj] += 1;
}
else if (rankedObj.Rank == max && maxOccurences > 1) // current rankedObj Tied for win
{
dictionaryDraws[rankedObj] += 1;
}
}
runOuts++;
}
}
class RankedObject
{
int rank;
double winEquity;
double drawEquity;
public int Rank { get => rank; set => rank = value; }
public double WinEquity { get => winEquity; set => winEquity = value; }
public double DrawEquity { get => drawEquity; set => drawEquity = value; }
public override string ToString()
{
return "Win Equity: " + winEquity + ", Draw Equity: " + drawEquity;
}
}
Related
I'm working on an assignment, where I have to make an application where you can throw 1-4 dice. The results are then added to a list.
However, if any of them is a 6, that one isn't added to the list, instead 2 additional dice are thrown.
As long as a die returns a 6, 2 more dice have to be thrown, until no die returns a 6.
Does anyone here know how to solve this? My programming skills are really basic, and I haven't used them much since last year.
for (int i = 0; i < qty; i++)
{
int diceNr = RollDice(random);
dicelist.Add(diceNr);
Console.WriteLine(diceNr);
if (diceNr == 6)
{
dicelist.Remove(diceNr);
Console.WriteLine("You got a six, that means you get 2 extra throws!");
for (int x = 0; x < 2; x++)
{
diceNr = RollDice(random);
dicelist.Add(diceNr);
}
You can try using a while loop as follows:
int i = quantity; #initialize a variable to your maximum number of throws
while(i > 0){ #until you have throws yet
i--; #this is the equivalent of one throw
int diceNr = RollDice(random);
dicelist.Add(diceNr);
Console.WriteLine(diceNr);
if(diceNr == 6){
Console.WriteLine("You got a six, that means you get 2 extra throws!");
i = i + 2; #add your bonus throws
}
}
You can use a while loop that exits once you are out of rolls. If you roll a six, add two more to the remaining quantity otherwise add the rolled value to the list.
int qty = 6;
// decrement remaining quantity each iteration
// until zero rolls remain
while(qty-- > 0)
{
int diceNr = RollDice(random);
Console.WriteLine(diceNr);
if (diceNr == 6)
{
// rolled six, add two more rolls
Console.WriteLine("You got a six, that means you get 2 extra throws!");
qty += 2;
}
else
{
// not six, add to list
dicelist.Add(diceNr);
}
}
// output all the non-six values
var allRolls = string.Join(",", diceList);
Console.WriteLine("All rolls: " + allRolls);
You could also do this with recursion (though I don't recommend it for this problem):
private static void Play(List<int> diceList, Random random, int rolls)
{
// base case, no rolls remain
if (rolls == 0)
return;
int diceNr = RollDice(random);
Console.WriteLine(diceNr);
if (diceNr == 6)
{
Console.WriteLine("You got a six, that means you get 2 extra throws!");
// add one to rolls since we are "reusing" this slot
// adding two would give us one more roll than we really want
rolls++
}
else
{
diceList.Add(diceNr);
// decrement rolls by one
rolls--;
}
// recursively call Play with updated roll count
// which is either original + 1 OR original - 1
Play(diceList, random, rolls);
}
private static int RollDice(Random r)
{
return r.Next(1, 7);
}
public static void Main()
{
var diceList = new List<int>();
var random = new Random();
int qty = 6;
Play(diceList, random, qty);
// output all the non-six values
var allRolls = string.Join(",", diceList);
Console.WriteLine("All rolls: " + allRolls);
}
My (readable) solution would look like:
class Program
{
static void Main(string[] args)
{
var game = new Game(4);
game.Play();
}
}
public class Game
{
private readonly int _noOfDices;
private readonly List<int> _result;
private readonly Random _random = new Random();
public Game(int noOfDices)
{
_noOfDices = noOfDices;
_result = new List<int>();
}
public void RollDice()
{
var no = _random.Next(1, 7);
if (no == 6)
{
RollDice();
RollDice();
}
else
{
_result.Add(no);
}
}
public void Play()
{
for (var i = 1; i <= _noOfDices; i++)
{
RollDice();
}
Console.WriteLine($"Output: {string.Join(',',_result)}");
}
}
Output:
I want to read data from my Accelerometer Sensor and compare them if the first number of the float changes. I have some problem to unregister the listener or pause in order to compare and see if the average/Note has increased by a full Int for example "Note: 5.677" increases to "Note:6.234" then it supposed to be recognized as an event.
I have converted them into Ints so I can check if they are equal or not.
I already have tried to delay it with Thread.Sleep and pause but doesnt work.
Maybe because of Lock(_synlock) ?
public void OnSensorChanged(SensorEvent e)
{
lock (_syncLock)
{
avg = e.Values.Average();
_sensorTextView.Text = string.Format("x={0:f}, y={1:f}, z={2:f}", e.Values[0], e.Values[1], e.Values[2]);
_sensorTextView2.Text = string.Format("Note: {0}", avg);
note1 = e.Values.Average();
//Thread.Sleep(500);
//base.OnPause();
//_sensorManager.UnregisterListener(this);
//base.OnResume();
//_sensorManager.RegisterListener(this, _sensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Ui);
//_sensorTextView.Text = string.Format("x={0:f}, y={1:f}, z={2:f}", e.Values[0], e.Values[1], e.Values[2]);
//avg = e.Values.Average();
//_sensorTextView2.Text = string.Format("Note: {0}", avg);
//note2 = e.Values.Average();
}
int noteInt1 = Convert.ToInt32(note1);
int noteInt2 = Convert.ToInt32(note2);
//Thread.Sleep(2000); "zeige alle 2 sekunden an"
List<double> eventnumbers = new List<double> { };
if (noteInt1 != noteInt2)
{
avg = e.Values.Average();
//Console.WriteLine("bye");
_sensorTextView2.Text = string.Format("Note: {0}", avg);
//foreach(SensorEvent e){
eventnumbers.Add(new double()); //Value of avg is the value of the eventnumber element
eventnumbers.ForEach(Console.WriteLine);
}
}
UPDATE :
public void OnSensorChanged(SensorEvent e)
{
lock (_syncLock)
{
_sensorTextView.Text = string.Format("x={0:f}, y={1:f}, y={2:f}", e.Values[0], e.Values[1], e.Values[2]);
//_sensorTextView2.Text = string.Format("Note: {0}", e.Values.Average());
avg = e.Values.Average();
}
eventCounter();
}
public void eventCounter()
{
eventnumbers.Add(avg); //add number to our buffer
Console.WriteLine(avg);
eventnumbers.Add(avg+1); //adding a number different of our first one to see if the method works
Console.WriteLine(avg+1);
while (eventnumbers.Count >= 1) //as long as two elements included
{
for (int puffer = 0; puffer <= 10; puffer++) //buffer of 10 Elements
{
for (int i = 0; i < eventnumbers.Count; i++) //compare first number of our buffer
{
note1 = eventnumbers[i]; //remember value of first element
Console.WriteLine(note1);
Console.WriteLine("i ist:" + i);
for (int j = 1; j <= eventnumbers.Count; j++) //with the second number of our buffer
{
Console.WriteLine("j ist:" + j);
note2 = eventnumbers[j]; //remember value of second element
Console.WriteLine(note2);
}
}
while (eventnumbers.Count >= 1) //as long as two elements included
{
try
{
noteInt1 = Convert.ToInt32(note1); //double to Int
noteInt2 = Convert.ToInt32(note2);
if (noteInt1 != noteInt2) //we parse to int in order to compare if event has changed
{
_sensorTextView2.Text = string.Format("Note: {0}", avg); //if yes update our displaying mark/number
eventcounters.Add(avg); //add element to elementcounter
}
break; //
}
catch (System.ArgumentOutOfRangeException) //for the case if there are less than 2 elements to compare
{
eventcounters.ForEach(Console.WriteLine); //return all marks(numbers) from our eventcounter
}
break;
} break;
}
//throw new NotImplementedException();
}
eventnumbers.Clear();
}
My Problem is that I do not get another (different) value when I call e.Value.Average(). I need to do it outside the method and call onSensorChanged another time but i dont know how to do that since I need to create another event, right? thats why I have used e1 and e2 but I think I miss something with the initialization i guess.
This is how I have tried so far creating two events:
public class MainActivity : Activity, ISensorEventListener
{
static readonly object _syncLock = new Object();
SensorManager _sensorManager;
TextView _sensorTextView;
TextView _sensorTextView2;
double note1;
double note2;
double avg;
SensorEvent e1;
SensorEvent e2;
my one create():
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.activity_main);
_sensorManager = (SensorManager)GetSystemService(SensorService);
_sensorTextView = FindViewById<TextView>(Resource.Id.accelerometer_text);
_sensorTextView2 = FindViewById<TextView>(Resource.Id.accelerometer_note);
e1 = (SensorEvent)GetSystemService(ISensorEventListener);
e2 = (SensorEvent)GetSystemService(ISensorEventListener);
displayMark();
ISensorEventListener is marked a wrong btw
public void displayMark()
{
OnSensorChanged(e1);
note1 = e1.Values.Average();
OnSensorChanged(e2);
note2 = e2.Values.Average();
int noteInt1 = Convert.ToInt32(note1);
int noteInt2 = Convert.ToInt32(note2);
Console.WriteLine(noteInt1);
Console.WriteLine(noteInt2);
List<double> eventnumbers = new List<double> { };
if (noteInt1 != noteInt2)
{
avg = e2.Values.Average();
Console.WriteLine("bye");
_sensorTextView2.Text = string.Format("Note: {0}", avg);
//foreach(SensorEvent e){
eventnumbers.Add(new double()); //Value of avg is the value of the eventnumber element
}
eventnumbers.ForEach(Console.WriteLine);
I'm just going to deal with the general approach here. Rather than trying to wait in an event for some new data I would use the events to record a value and then compare the new one to the last one. So outside the function would be a variable something like:
private int previousValue;
Then when the function is called it compares the 'new' value to this previous one:
public void OnSensorChanged(SensorEvent e)
{
// Can't tell if this is required with information available
lock (_syncLock)
{
// Capture the 'new' data to a local variable
var newValue = e.Values.Average();
if (newValue != previousValue)
{
// Value has changed by required amount so do something here
}
// Update the previous so next we we use this as our reference value
previousValue = newValue;
}
This isn't a full solution but should be a better starting point for developing one.
I've been having trouble running multiple tasks with heavy operations.
It seems as if the task processes is killed before all the operations are complete.
The code here is an example code I used to replicate the issue. If I add something like Debug.Write(), the added wait for writing fixes the issue. The issue is gone if I test on a smaller sample size too. The reason there is a class in the example below is to create complexity for the test.
The real case where I encountered the issue first is too complicated to explain for a post here.
public static class StaticRandom
{
static int seed = Environment.TickCount;
static readonly ThreadLocal<Random> random =
new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref seed)));
public static int Next()
{
return random.Value.Next();
}
public static int Next(int maxValue)
{
return random.Value.Next(maxValue);
}
public static double NextDouble()
{
return random.Value.NextDouble();
}
}
// this is the test function I run to recreate the problem:
static void tasktest()
{
var testlist = new List<ExampleClass>();
for (var index = 0; index < 10000; ++index)
{
var newClass = new ExampleClass();
newClass.Populate(Enumerable.Range(0, 1000).ToList());
testlist.Add(newClass);
}
var anotherClassList = new List<ExampleClass>();
var threadNumber = 5;
if (threadNumber > testlist.Count)
{
threadNumber = testlist.Count;
}
var taskList = new List<Task>();
var tokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = tokenSource.Token;
int stuffPerThread = testlist.Count / threadNumber;
var stuffCounter = 0;
for (var count = 1; count <= threadNumber; ++count)
{
var toSkip = stuffCounter;
var threadWorkLoad = stuffPerThread;
var currentIndex = count;
// these ifs make sure all the indexes are covered
if (stuffCounter + threadWorkLoad > testlist.Count)
{
threadWorkLoad = testlist.Count - stuffCounter;
}
else if (count == threadNumber && stuffCounter + threadWorkLoad < testlist.Count)
{
threadWorkLoad = testlist.Count - stuffCounter;
}
taskList.Add(Task.Factory.StartNew(() => taskfunc(testlist, anotherClassList, toSkip, threadWorkLoad),
cancellationToken, TaskCreationOptions.None, TaskScheduler.Default));
stuffCounter += stuffPerThread;
}
Task.WaitAll(taskList.ToArray());
}
public class ExampleClass
{
public ExampleClassInner[] Inners { get; set; }
public ExampleClass()
{
Inners = new ExampleClassInner[5];
for (var index = 0; index < Inners.Length; ++index)
{
Inners[index] = new ExampleClassInner();
}
}
public void Populate(List<int> intlist) {/*adds random ints to the inner class*/}
public ExampleClass(ExampleClass copyFrom)
{
Inners = new ExampleClassInner[5];
for (var index = 0; index < Inners.Length; ++index)
{
Inners[index] = new ExampleClassInner(copyFrom.Inners[index]);
}
}
public class ExampleClassInner
{
public bool SomeBool { get; set; } = false;
public int SomeInt { get; set; } = -1;
public ExampleClassInner()
{
}
public ExampleClassInner(ExampleClassInner copyFrom)
{
SomeBool = copyFrom.SomeBool;
SomeInt = copyFrom.SomeInt;
}
}
}
static int expensivefunc(int theint)
{
/*a lot of pointless arithmetic and loops done only on primitives and with primitives,
just to increase the complexity*/
theint *= theint + 1;
var anotherlist = Enumerable.Range(0, 10000).ToList();
for (var index = 0; index < anotherlist.Count; ++index)
{
theint += index;
if (theint % 5 == 0)
{
theint *= index / 2;
}
}
var yetanotherlist = Enumerable.Range(0, 50000).ToList();
for (var index = 0; index < yetanotherlist.Count; ++index)
{
theint += index;
if (theint % 7 == 0)
{
theint -= index / 3;
}
}
while (theint > 8)
{
theint /= 2;
}
return theint;
}
// this function is intentionally creating a lot of objects, to simulate complexity
static void taskfunc(List<ExampleClass> intlist, List<ExampleClass> anotherClassList, int skip, int take)
{
if (take == 0)
{
take = intlist.Count;
}
var partial = intlist.Skip(skip).Take(take).ToList();
for (var index = 0; index < partial.Count; ++index)
{
var testint = expensivefunc(index);
var newClass = new ExampleClass(partial[index]);
newDna.Inners[StaticRandom.Next(5)].SomeInt = testint;
anotherClassList.Add(new ExampleClass(newClass));
}
}
The expected result is that the list anotherClassList will be the same size as testlist and this happens when the lists are smaller or the complexity of the task operations is smaller. However, when I increase the volume of operations, the anotherClassList has a few indexes missing and sometimes some of the indexes in the list are null objects.
Example result:
Why does this happen, I have Task.WaitAll?
Your problem is it's just not thread-safe; you just can't add to a list<T> in a multi-threaded environment and expect it to play nice.
One way is to use lock or a thread safe collection, but I feel this all should be refactored (my OCD is going off all over the place).
private static object _sync = new object();
...
private static void TaskFunc(List<ExampleClass> intlist, List<ExampleClass> anotherClassList, int skip, int take)
{
...
var partial = intlist.Skip(skip).Take(take).ToList();
...
// note that locking here will likely drastically decrease any performance threading gain
lock (_sync)
{
for (var index = 0; index < partial.Count; ++index)
{
// this is your problem, you are adding to a list from multiple threads
anotherClassList.Add(...);
}
}
}
In short, I think you need to better thinking about the threading logic of your method, identify what you are trying to achieve, and how to make it conceptually thread safe (while keeping your performance gains).
After TheGeneral enlightened me that Lists are not thread safe, I changed the List to which I was adding in a thread, to an Array type and this fixed my issue.
This is for a data structures and algorithms class. We're just starting out with bubble sort. The instructions were to generate random, unique integers and sort them using the sorting technique of the lecture. It will be required to add different sorting techniques as well.
To generate the list of random numbers, I generated a list and then shuffled the list using the fisher-yates algorithm. So I have my unique, sorted list of whatever size I choose.
I'm getting stuck because after I generate the random list, I am having problems accessing the list to run it through BubbleSort.
Is there any way I can do this?
class Algorithms
{
static void Main(string[] args)
{
string response = "";
//Main Console Menu
while (response != "exit")
{
Console.WriteLine("Type help for list of commands");
response = Console.ReadLine();
//List<int> toSort = new List<int>();
if (response.StartsWith("exit"))
{
Environment.Exit(0);
}
else if (response.ToLower().StartsWith("help"))
{
Help(response);
}
else if (response.ToLower().StartsWith("generate"))
{
// Shuffle(Generate(response));
// have been using the line above but adding next line for
//an idea of my problem
List<int> toSort = Shuffle(Generate(response));
}
else if (response.ToLower().StartsWith("bubble"))
{
//This doesn't work and I'm trying to figure out how it can
BubbleSort(toSort);
}
}
}
//Displays help information
public static void Help(string input)
{
Console.WriteLine("\ngenerate <integer> -- Generates a data set of intended amount of integers\n"+
"algorithm <algorithm type> -- Choose which algorithm to sort data\nexit -- exit application\n" );
}
//Generates List of integers from 0 to number choosen by user
public static List<int> Generate(string size)
{
int cutString = size.Length - 9;
string sizeSubset = size.Substring(9, cutString);
List<int> numGen = new List<int>();
int dataSetSize = Convert.ToInt32(sizeSubset);
for(int i = 0; i <= dataSetSize; i++)
{
numGen.Add(i);
// Console.WriteLine(numGen[i]);
}
return numGen;
}
//Use Fisher-Yates algorithm to shuffle the list.
static Random randomize = new Random();
public static List<int> Shuffle(List<int>makeRandom)
{
List<int> shuffled = new List<int>();
int n = makeRandom.Count;
while (n > 1)
{
n--;
int k = randomize.Next(n + 1);
int value = makeRandom[k];
makeRandom[k] = makeRandom[n];
makeRandom[n] = value;
shuffled.Add(value);
Console.WriteLine(value);
}
return shuffled;
}
public static void BubbleSort(List<int>input)
{
for(int i = 0; i <= input.Count; i++)
{
for (int j = 0; j <= (input.Count - 1); j++)
{
if (input[j] > input[j + 1])
{
int temp = input[j];
input[j] = input[j + 1];
input[j + 1] = temp;
Console.WriteLine("hello");
}
}
}
}
}
}
You defined list in scope of else if (response.ToLower().StartsWith("generate")) code block, so it is not accessible outside of that block. Move declaration to Main method scope, like this:
static void Main(string[] args)
{
string response = "";
//define your list here.
List<int> toSort = new List<int>();
//Main Console Menu
while (response != "exit")
{
Console.WriteLine("Type help for list of commands");
response = Console.ReadLine();
if (response.StartsWith("exit"))
{
Environment.Exit(0);
}
else if (response.ToLower().StartsWith("help"))
{
Help(response);
}
else if (response.ToLower().StartsWith("generate"))
{
toSort = Shuffle(Generate(response));
}
else if (response.ToLower().StartsWith("bubble"))
{
List<int> sortedList = BubbleSort(toSort);
}
}
}
For a school project in learning c# I am making a data collection console application which saves floating point entries for 4 different locations along with the time/date, and user who recorded the entry. I am required to use a multi dimensional struct array.
I need to have a view that displays the average of the values, along with the minimum and maximum values and the first and last date. I've got the average figured out by counting through the values and adding cumulatively but I can't figure out how to find the minimum and maximum values.
I tried searching and came across this page: http://www.dotnetperls.com/max
I tried to implement this syntax into my code to no avail due to it being a much more complex array.
It worked in my test with integers:
class Program
{
static int[][] intarray = new int[4][] { new int[10], new int[10], new int[10], new int[10] };
static void Main(string[] args)
{
intarray[0][0] = 5;
intarray[0][1] = 3;
intarray[0][2] = 10;
intarray[0][3] = 4;
intarray[0][4] = 2;
Console.WriteLine(intarray[0].Max());
Console.ReadLine();
}
}
The above code perfectly displays the number 10! :)
But when I tried to implement this in to my program with a struct array, it doesn't work:
class Program
{
static byte location = 0;
static float entriesmin;
static float entriesmax;
static Entry[][] entriesarray = new Entry[4][] { new Entry[10], new Entry[10], new Entry[10], new Entry[10] };
struct Entry
{
public float value;
public string user;
public DateTime datetime;
}
static byte LoopEntries(bool display)
{
float runningtotal = 0;
byte entrycount = 0;
foreach (Entry entry in entriesarray[0])
{
if (entry.user != null)
{
if (display)
{
string ten;
if (entrycount == 9)
{
ten = " #";
}
else
{
ten = " #";
}
Console.WriteLine(ten + (entrycount + 1) + " " + entry.datetime + " " + entry.user + new string(' ', 16 - entry.user.Length) + entry.value);
}
runningtotal += entry.value;
entrycount += 1;
}
}
entriesmin = (entriesarray[location]).value.Min();
entriesmax = (entriesarray[location]).value.Max();
if (entrycount == 0 && display)
{
Console.WriteLine("No entries to show!");
}
return entrycount;
}
I need to hand this project in on Monday! I really hope someone can help me! ;)
What you have is not a multidimensional array, it's an array of array (a.k.a. a jagged array), but you work with them in a similar way.
To loop through the array of arrays you need a loop in a loop:
foreach (Entry[] arr in entriesarray) {
foreach (Entry entry in arr) {
// ...
}
}
You could use the Min and Max extension methods to get the minimum and maximum value of each inner array, but you still would have to find the minimum and maximum between those values. As you are already looping through all the entries anyway to get the average you can just keep a record of the smallest and largest values found:
float runningtotal = 0;
int entrycount = 0;
float min = float.MaxValue;
float max = float.MinValue;
foreach (Entry[] arr in entriesarray) {
foreach (Entry entry in arr) {
runningtotal += entry.value;
entrycount++;
if (entry.value < min) {
min = entry.value;
}
if (entry.value > max) {
max = entry.value;
}
}
}