When I run the following code in Mono (and not in Microsoft's C# apparently) in the monodevelop IDE. I get the same sequence of random numbers every time (00111111110110001001). If I change the range to something else e.g. r.Next(0, 5) then I do get random values. This seems very weird to me .. is this a bug or am I doing something dumb?
NOTE: it seems sometimes these numbers are negated.. e.g. I see 11000000001001110110 occasionally.
using System;
namespace TestRNG
{
class MainClass
{
public static void Main (string[] args)
{
Random r = new Random ();
for (int i = 0; i < 20; i++) {
Console.Write(r.Next(0, 2));
}
Console.WriteLine();
}
}
}
This is not the "Calling Next() on instances of Random called too closely together and therefore seeded with the same seed from the system clock problem".
Using the following code:
using System;
namespace TestRNG
{
class MainClass
{
public static void Main (string[] args)
{
Random r = new Random (Guid.NewGuid().ToByteArray()[0]);
for (int i = 0; i < 20; i++) {
int rn = r.Next ();
Console.WriteLine(rn + " " + (rn % 2));
}
Console.WriteLine();
}
}
}
I see that I get different values for rn every time but the sequence of values for rn % 2, which is what I suspect r.Next() is returning, is the same old values I always see. This leads me to believe that the Russian? fellow who posted an answer before and was down-voted to oblivion was correct (he's subsequently removed his answer). See http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx for example.
Based on one of the comments below this may only be a mono implementation thing.
Well, extending on what swistak said(because i used the Guid class too), this is the code i made for your issue, is already tested and it works:
using System;
using System.Linq;
namespace pruebaDeNumerosAleatorios
{
class MainClass
{
public static int RandomNumber()
{
Random x = new Random(Guid.NewGuid().ToByteArray().First());
return x.Next(0, 20);
}
public static void Main(string[] args)
{
for (int i = 0; i < 20; i++)
Console.WriteLine(RandomNumber());
}
}
}
As it was said before, you don't give the time to the internal clock (which you are using as seed) to change between iterations so, the number generated is the same. What i did here is implement the Guid class which generates a 'unique' number, convert it as an array of bytes and just used the first element of the array as seed.
i did this in a method because that guarantees me that everytime the method is called a diferent number is generated by the Guid class, so im using a different seed for the random number.
You can generate "more random" number without much higher impact on performance by using Guid class:
Random r = new Random(Guid.NewGuid().ToByteArray()[0]);
Edit: The problem with getting similar values every time is because Random.Next() is taking value from current system clock, so probably there isn't much difference in time between each compilation to generate varied values. Try running your code in a loop and values should be more varied.
Related
I tried to sort Guids generated by UuidCreateSequential, but I see the results are not correct, am I mising something? here is the code
private class NativeMethods
{
[DllImport("rpcrt4.dll", SetLastError = true)]
public static extern int UuidCreateSequential(out Guid guid);
}
public static Guid CreateSequentialGuid()
{
const int RPC_S_OK = 0;
Guid guid;
int result = NativeMethods.UuidCreateSequential(out guid);
if (result == RPC_S_OK)
return guid;
else throw new Exception("could not generate unique sequential guid");
}
static void TestSortedSequentialGuid(int length)
{
Guid []guids = new Guid[length];
int[] ids = new int[length];
for (int i = 0; i < length; i++)
{
guids[i] = CreateSequentialGuid();
ids[i] = i;
Thread.Sleep(60000);
}
Array.Sort(guids, ids);
for (int i = 0; i < length - 1; i++)
{
if (ids[i] > ids[i + 1])
{
Console.WriteLine("sorting using guids failed!");
return;
}
}
Console.WriteLine("sorting using guids succeeded!");
}
EDIT1:
Just to make my question clear, why the guid struct is not sortable using the default comparer ?
EDIT 2:
Also here are some sequential guids I've generated, seems they are not sorted ascending as presented by the hex string
"53cd98f2504a11e682838cdcd43024a7",
"7178df9d504a11e682838cdcd43024a7",
"800b5b69504a11e682838cdcd43024a7",
"9796eb73504a11e682838cdcd43024a7",
"c14c5778504a11e682838cdcd43024a7",
"c14c5779504a11e682838cdcd43024a7",
"d2324e9f504a11e682838cdcd43024a7",
"d2324ea0504a11e682838cdcd43024a7",
"da3d4460504a11e682838cdcd43024a7",
"e149ff28504a11e682838cdcd43024a7",
"f2309d56504a11e682838cdcd43024a7",
"f2309d57504a11e682838cdcd43024a7",
"fa901efd504a11e682838cdcd43024a7",
"fa901efe504a11e682838cdcd43024a7",
"036340af504b11e682838cdcd43024a7",
"11768c0b504b11e682838cdcd43024a7",
"2f57689d504b11e682838cdcd43024a7"
First off, let's re-state the observation: when creating sequential GUIDs with a huge time delay -- 60 billion nanoseconds -- between creations, the resulting GUIDs are not sequential.
am I missing something?
You know every fact you need to know to figure out what is going on. You're just not putting them together.
You have a service that provides numbers which are both sequential and unique across all computers in the universe. Think for a moment about how that is possible. It's not a magic box; someone had to write that code.
Imagine if you didn't have to do it using computers, but instead had to do it by hand. You advertise a service: you provide sequential globally unique numbers to anyone who asks at any time.
Now, suppose I ask you for three such numbers and you hand out 20, 21, and 22. Then sixty years later I ask you for three more and surprise, you give me 13510985, 13510986 and 13510987. "Wait just a minute here", I say, "I wanted six sequential numbers, but you gave me three sequential numbers and then three more. What gives?"
Well, what do you suppose happened in that intervening 60 years? Remember, you provide this service to anyone who asks, at any time. Under what circumstances could you give me 23, 24 and 25? Only if no one else asked within that 60 years.
Now is it clear why your program is behaving exactly as it ought to?
In practice, the sequential GUID generator uses the current time as part of its strategy to enforce the globally unique property. Current time and current location is a reasonable starting point for creating a unique number, since presumably there is only one computer on your desk at any one time.
Now, I caution you that this is only a starting point; suppose you have twenty virtual machines all in the same real machine and all trying to generate sequential GUIDs at the same time? In these scenarios collisions become much more likely. You can probably think of techniques you might use to mitigate collisions in these scenarios.
After researching, I can't sort the guid using the default sort or even using the default string representation from guid.ToString as the byte order is different.
to sort the guids generated by UuidCreateSequential I need to convert to either BigInteger or form my own string representation (i.e. hex string 32 characters) by putting bytes in most signification to least significant order as follows:
static void TestSortedSequentialGuid(int length)
{
Guid []guids = new Guid[length];
int[] ids = new int[length];
for (int i = 0; i < length; i++)
{
guids[i] = CreateSequentialGuid();
ids[i] = i;
// this simulates the delay between guids creation
// yes the guids will not be sequential as it interrupts generator
// (as it used the time internally)
// but still the guids should be in increasing order and hence they are
// sortable and that was the goal of the question
Thread.Sleep(60000);
}
var sortedGuidStrings = guids.Select(x =>
{
var bytes = x.ToByteArray();
//reverse high bytes that represents the sequential part (time)
string high = BitConverter.ToString(bytes.Take(10).Reverse().ToArray());
//set last 6 bytes are just the node (MAC address) take it as it is.
return high + BitConverter.ToString(bytes.Skip(10).ToArray());
}).ToArray();
// sort ids using the generated sortedGuidStrings
Array.Sort(sortedGuidStrings, ids);
for (int i = 0; i < length - 1; i++)
{
if (ids[i] > ids[i + 1])
{
Console.WriteLine("sorting using sortedGuidStrings failed!");
return;
}
}
Console.WriteLine("sorting using sortedGuidStrings succeeded!");
}
Hopefully I understood your question correctly. It seems you are trying to sort the HEX representation of your Guids. That really means that you are sorting them alphabetically and not numerically.
Guids will be indexed by their byte value in the database. Here is a console app to prove that your Guids are numerically sequential:
using System;
using System.Linq;
using System.Numerics;
class Program
{
static void Main(string[] args)
{
//These are the sequential guids you provided.
Guid[] guids = new[]
{
"53cd98f2504a11e682838cdcd43024a7",
"7178df9d504a11e682838cdcd43024a7",
"800b5b69504a11e682838cdcd43024a7",
"9796eb73504a11e682838cdcd43024a7",
"c14c5778504a11e682838cdcd43024a7",
"c14c5779504a11e682838cdcd43024a7",
"d2324e9f504a11e682838cdcd43024a7",
"d2324ea0504a11e682838cdcd43024a7",
"da3d4460504a11e682838cdcd43024a7",
"e149ff28504a11e682838cdcd43024a7",
"f2309d56504a11e682838cdcd43024a7",
"f2309d57504a11e682838cdcd43024a7",
"fa901efd504a11e682838cdcd43024a7",
"fa901efe504a11e682838cdcd43024a7",
"036340af504b11e682838cdcd43024a7",
"11768c0b504b11e682838cdcd43024a7",
"2f57689d504b11e682838cdcd43024a7"
}.Select(l => Guid.Parse(l)).ToArray();
//Convert to BigIntegers to get their numeric value from the Guids bytes then sort them.
BigInteger[] values = guids.Select(l => new BigInteger(l.ToByteArray())).OrderBy(l => l).ToArray();
for (int i = 0; i < guids.Length; i++)
{
//Convert back to a guid.
Guid sortedGuid = new Guid(values[i].ToByteArray());
//Compare the guids. The guids array should be sequential.
if(!sortedGuid.Equals(guids[i]))
throw new Exception("Not sequential!");
}
Console.WriteLine("All good!");
Console.ReadKey();
}
}
I am a newbie C# learner and building a system to generate problem sheets from an ordered set of questions. Each problem sheet has 30 question chosen randomly from the set of questions. Each problem sheet is uniquely identified by an integer which is used as the seed value.
As I don't know the internal details of how random generator works, I want to know whether or not the n-th invocation of Random.Next() with the same seed will always produce the same number regardless of the .NET version.
The minimal working example is as follows.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
const int seed = 12345;
Random rnd = new Random(seed);
for (int x = 0; x < 10; x++)
Console.WriteLine(rnd.Next());
}
}
}
Maybe read the documentation:
Notes to Callers
The implementation of the random number generator in the Random class is not guaranteed to remain the same across major versions of the .NET Framework. As a result, your application code should not assume that the same seed will result in the same pseudo-random sequence in different versions of the .NET Framework.
Yes! you have a possibility to get same random number will be generated if you provide same seed
Random rnd=new Random(5);
for(int i=0;i<10;i++)
{
Console.WriteLine(rnd.Next());
}
Console.WriteLine(".....");
Random rnd1 = new Random(5);
for (int i = 0; i < 10; i++)
{
Console.WriteLine(rnd1.Next());
}
Console.ReadLine();
############### The output
726643700
610783965
564707973
1342984399
995276750
1993667614
314199522
2041397713
1280186417
252243313
.....
726643700
610783965
564707973
1342984399
995276750
1993667614
314199522
2041397713
1280186417
252243313
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 9 years ago.
// Create a string array that consists of ten lines.
string[] personalNumbers; // declare personalNumbers as a 10-element array
personalNumbers = new string[10]; //= { "First number", "Second number", "Third line", etc}
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
Random random = new Random();
int randomNumber = random.Next(1, 50);
string RandomNumberText = Convert.ToString(randomNumber);
personalNumbers[i] = RandomNumberText;
}
Hi, I know that this SEEMS to be a duplicate of previously asked questions, but I am trying to
generate a series of random numbers between 1 and 50 to populate an array
The problem is, if I do it as we were taught in class, each number is the same
I know that the problem is that the tight loop causes the random to be seeded with the same number
What NONE of the other threads addresses however, is HOW to fix this problem when using a loop iteration....
All of the explanations thus far are so far advanced beyond our level that I (and the other askers BTW) have no clue how to implement them as a solution, which I also cannot submit in class as they are techniques that we have not covered
The tutorials at Microsoft insist that putting the random inside the loop is the right solution
I've tried putting an instance of random outside the loop and then calling it from inside the loop but this has caused an exception
Is there a straightforward way to use random to create a series of random numbers that doesn't run into this problem?
Create the random instance outside of the loop:
Random random = new Random();
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
MSDN:
The random number generation starts from a seed value. If the same
seed is used repeatedly, the same series of numbers is generated. One
way to produce different sequences is to make the seed value
time-dependent, thereby producing a different series with each new
instance of Random. By default, the parameterless constructor of the
Random class uses the system clock to generate its seed value, while
its parameterized constructor can take an Int32 value based on the
number of ticks in the current time. However, because the clock has
finite resolution, using the parameterless constructor to create
different Random objects in close succession creates random number
generators that produce identical sequences of random numbers.
You have to define the Random object outside the loop and just get a number each time inside the loop. If you create it each time again, it will be created with the same initial value because the interval between creations is too small.
Random random = new Random();
for (int i = 0; i < 9; i++) {
int randomNumber = random.Next(1, 50);
}
I've tried putting an instance of random outside the loop and then
calling it from inside the loop but this has caused an exception
Here are two concrete examples, one for a Console app, and the other for a WinForms app.
This is one way to declare it in a Console app. random can be used from anywhere within the application, even in methods other than Main():
class Program
{
private static Random random = new Random();
static void Main(string[] args)
{
// ... code ...
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
int randomNumber = random.Next(1, 50);
personalNumbers[i] = randomNumber.ToString();
}
// ... code ...
}
}
This is one way to declare it for use in a WinForms app. random in this example can be used anywhere within Form1:
public partial class Form1 : Form
{
private Random random = new Random();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// ... code ...
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
int randomNumber = random.Next(1, 50);
personalNumbers[i] = randomNumber.ToString();
}
// ... code ...
}
}
This should cover most simple homework assignments. Nothing fancy here.
thank you for the input, it is much appreciated!
I have posted the complete code thus far, which is now giving me what seems like "random" numbers
in that they are always different when I run it
#Steve thank you...I have looked at those questions, but all of the solutions involve using some other technique than random() which I am not allowed to use
#Oerkelens thank you, when I moved the code for random() outside the loop, I got two possible results
one was a series of 9, 9-digit random numbers, or an exception that says
Error 1 A local variable named 'randomNumber' cannot be declared in this scope because
it would give a different meaning to'randomNumber', which is already used in a 'parent or current' scope to denote something else
I have posted the larger bit of code to show what I have changed to get it to work...I don't really understand how to properly call the random() from within the loop, but for some reason, having the same line both inside and outside of the loop did the trick
#Preston - we don't have a textbook for this course, and we are only allowed to use techniques that are contained within the Microsoft C# video tutorials by Bob Tabor (learnvisualstudiodotnet) and Envato (learn C# in 30 days)
I apologize if this all seems obvious to you, but we are in the position of being told that half-way through the course that we are switching from learning to program in Visual Basic to C#, so all of our work now needs to be re-written in C#, without any particular instruction in how to how to use this language...needless to say, it is a huge stress and we are being left without any resources to do this, so much of what we are doing is guesswork
the more complete code that is "working"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace GuessingGameProgram
{
class Program
{
int randNum;
static void Main(string[] args)
{
// Create a string array that consists of ten lines.
string[] personalNumbers; // declare personalNumbers as a 10-element array
personalNumbers = new string[10]; //= { "First number", "Second number", "Third line", etc}
Random outsideLoopRandom = new Random();
int randomNumber = outsideLoopRandom.Next(1, 50);
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
randomNumber = outsideLoopRandom.Next(1, 50);
string RandomNumberText = Convert.ToString(randomNumber);
personalNumbers[i] = RandomNumberText;
}
// WriteAllLines creates a file, writes a collection of strings to the file,
// and then closes the file.
//System.IO.File.WriteAllLines(#"C:\Users\Public\TestFolder\WriteLines.txt", lines);
foreach (string i in personalNumbers) // this is just a test to see what the output is
{
Console.Write("{0} ", i);
}
Console.ReadLine();
}
}
}
//randNum = Random.Equals(1, 50);
//StreamReader myReader = new StreamReader("personalNumbers.txt");
//string line = "";
//while (line != null)
//{
// line = myReader.ReadLine();
// if (line != null)
// Console.WriteLine(line);
//}
//myReader.Close();
//Console.ReadLine();
//personalNumbers = RandomNumbers.next(1, 10);
//int returnValue = personalNumbers.Next(1, 50);
//int Guess = 0;
//Console.WriteLine("Please guess a number between 1 and 50");
//Console.ReadLine();
////while (Guess = Convert.ToInt32(Console.Read());
//if (Guess < returnValue)
//{
// Console.WriteLine("Wrong! the number that I am thinking of is higher than " + Guess + ". Try again!");
// Console.ReadLine();
//}
//if (Guess > returnValue)
//{
// Console.WriteLine("Wrong! The number that I am thinking of is lower than " + Guess + ". Try again!");
// Console.ReadLine();
//}
// else if (Guess = returnValue)
// Console.WriteLine("Correct! The number that I was thinking of was " + Guess + ". Congratulations!");
// //{
//Console.WriteLine("Let's play a guessing game!")
//Console.WriteLine("")
//Console.WriteLine("guess a number between 1 and 10")
//Console.WriteLine("")
//randNum = randomGenerator.Next(1, 10)
//While userGuess <> randNum
// {
// userGuess = Console.ReadLine()
// }
// If userGuess > randNum Then
// Console.WriteLine("too high, guess again!")
// {
// If userGuess < randNum Then
// Console.WriteLine("too low, guess again!")
// }
// Else
//End While
//Console.WriteLine("Correct! the secret number is " & randNum)
//Console.ReadLine()
My program needs to:
a. Generate an array of 20 random integers from zero to nine. Search for the first occurrence, if any, of the number 7, and report its position in the array.
b. Repeat the computation of part a 1000 times, and for each position in the array, report the number of times that the first occurrence of a 7 in the array is at that position
However whenever I run the program I get strange results (different every time) such as:
No sevens found at any position
1000 sevens found at one position and no sevens found anywhere else
Hundreds of sevens found in 2 positions, and none found anywhere else.
Does anyone have an idea what is wrong with my program?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Week_6_Project_2
{
class Program
{
static int intArrayLength = 20;
static int[] resultsArray = new int[intArrayLength];
public static Array generateRandomArray() {
int[] randomNumberArray = new int[intArrayLength];
Random random = new Random();
int popcounter = 0;
while (popcounter < intArrayLength) {
randomNumberArray[popcounter] = random.Next(0, 10);
popcounter += 1;
}
return randomNumberArray;
}
public static void searchForSevens()
{
int counter = 0;
int[] randomArray = (int[])generateRandomArray();
while (counter < intArrayLength)
{
if (randomArray[counter] == 7)
{
resultsArray[counter] += 1;
counter = intArrayLength;
}
counter += 1;
}
}
static void Main()
{
int searchCounter = 0;
while (searchCounter < 1000)
{
searchForSevens();
searchCounter += 1;
}
int displayCounter = 0;
while (displayCounter < intArrayLength)
{
Console.WriteLine("Number of first occurrence of 7 at position {0} = {1}", displayCounter, resultsArray[displayCounter]);
displayCounter += 1;
}
Console.ReadLine();
}
}
}
Your main problem is that each searchForSevens() test only takes a small fraction of time and the Random class uses auto-seeding from the clock. The clock however has a limited resolution. The result is that many (sometimes all) of your random sequences will be the same. And at most you will have 2 or 3 different result sets.
The simple fix for this single-threaded program is to use 1 static instance of Random.
You're instantiating a new instance of Random every time you call the generateRandomArray method. Since the random number generator uses the current time as a seed, instantiating two Random instances at the same time results in the same numbers being generated, which explains your unexpected results.
To solve your problem, you should only instantiate one Random instance, store it in private field, and reuse it every time you call the Next method.
The problem I assume stems from the fact, that Random() uses current time as seed. And the computation happens so fast, that each time new Random() is called, it uses same time. So you get same sequence of numbers.
To fix this, you simply need to set seed by yourself, incremmenting it every cycle should be enough.
long base = DateTime.Now.TotalMilliseconds;
Random rand = new Random(base+searchCounter);
.. something like that.
I will not answer but will try to give an analogy for the people that think that they need more then one Random instance...
Suppose that you need to fill 6 sheets of paper with random numbers from 1-6. Ask yourself this: do you need 6 dices or one to do the job? If you answer that you need more than one dice, ask yourself this: how different or more random is throwing different dice instead of same dice every time?
I mean, if you throw ONE on a dice, next throw of a dice won't have any less chance to be ONE again than it would be any other number. It goes against intuition, but it is mathematically and statistically so.
In your original code, you're calling the Random method in rapid succession [broken example based on OP's original code], thus seeding the method with the same number, resulting in duplicate "random" numbers. Creating a static member will ensure randomness simply because you're only creating a single instance of it.
Try creating a single static instance of random like this. [static member example].
static readonly Random Random = new Random();
Based on this, here's how I would solve your particular problem.
using System;
namespace Week_6_Project_2
{
class Program
{
// ******************************************
// THIS IS A SINGLE INSTANCE OF Random.
// read below as to why I'm seeding the instantiation of Random();
static readonly Random Random = new Random(Guid.NewGuid().GetHashCode());
// ******************************************
private const int IntArrayLength = 20;
static readonly int[] ResultsArray = new int[IntArrayLength];
public static Array GenerateRandomArray()
{
var randomNumberArray = new int[IntArrayLength];
var popcounter = 0;
while (popcounter < IntArrayLength)
{
randomNumberArray[popcounter] = Random.Next(0, 10);
popcounter += 1;
}
return randomNumberArray;
}
public static void SearchForSevens()
{
var counter = 0;
var randomArray = (int[])GenerateRandomArray();
while (counter < IntArrayLength)
{
if (randomArray[counter] == 7)
{
ResultsArray[counter] += 1;
counter = IntArrayLength;
}
counter += 1;
}
}
static void Main()
{
var searchCounter = 0;
while (searchCounter < 1000)
{
SearchForSevens();
searchCounter += 1;
}
var displayCounter = 0;
while (displayCounter < IntArrayLength)
{
Console.WriteLine("Number of first occurrence of 7 at position {0} = {1}", displayCounter, ResultsArray[displayCounter]);
displayCounter += 1;
}
Console.ReadLine();
}
}
}
Further reading about Random()
Beyond the answer above, sometimes it is necessary to seed Random(int); (I like to use the HashCode of a Guid) to ensure further randomness. This is because the default seed uses the clock which from the docs [microsoft] has a finite resolution. If your class is instantiated multiple times in quick succession (< 16ms), you will get the same seed from the clock... this breaks stuff.
[example of seeded Random(int) run in rapid succession with random results]
"using the parameterless constructor to create different Random objects in close succession creates random number generators that produce identical sequences of random numbers."
hear me when I say that you should NOT instantiate a new Random on every iteration of a loop -- use a static member
Another valid reason to implement your own seed is when you want to recreate a random sequence [example of two identical lists based on same seed]. Re-using the same seed will recreate the sequence since the sequence is based on the seed.
note: others might say that seeding it is not necessary [link], but I personally believe that for the additional few keystrokes and the microscopic hit on the clock, you might as well increase the probability of a unique seed. It doesn't hurt anything, and in some situations it can help.
I'm sifting through some of my old bugs and while reviewing some nasty code I realized that my averaging or smoothing algorithm was pretty bad. I did a little research which led me to the "running mean" - makes sense, pretty straightforward. I was thinking through a possible implementation and realized that I don't know which collection would provide the type of "sliding" functionality that I need. In other words, I need to push/add an item to the end of the collection and then also pop/remove the first item from the collection. I think if I knew what this was called I could find the correct collection but I don't know what to search for.
Ideally a collection where you set the max size and anything added to it that exceeds that size would pop off the first item.
To illustrate, here is what I came up with while messing around:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
LinkedList<int> samples = new LinkedList<int>();
// Simulate packing the front of the samples, this would most like be a pre-averaged
// value from the raw samples
for (int i = 0; i < 10; i++)
{
samples.AddLast(0);
}
for (int i = 0; i < 100; i++)
{
// My attempt at a "sliding collection" - not really sure what to call it but as
// an item is added the first item is removed
samples.RemoveFirst();
samples.AddLast(i);
foreach (int v in samples)
{
Console.Write("{0:000} ", v);
}
Console.WriteLine(String.Empty);
}
Console.ReadLine();
}
}
}
As you can see I am manually handling the removal of the first item. I'm just asking if there is a standard collection that is optimized for this type of use?
It appears that you're looking for a Circular Buffer. Here's a .NET implementation on CodePlex. You may also want to look at this question: How would you code an efficient Circular Buffer in Java or C#?
From the sample you've provided, it isn't clear how exactly this relates to an online-mean algorithm. If the only operation allowed on the buffer is to append; it should be trivial to cache and update the "total" inside the buffer (add the new value, subtract the removed one); making the maintaining of the mean an O(1) operation for every append. In this case, the buffer is effectively holding the Simple Moving Average (SMA) of a series.
Have you had a look at Queue Class
Does a List satisfy your needs?
List<String> myList = new List<String>();
myList.Add("Something to the end");
myList.RemoveAt(0);
#Ani - I'm creating a new Answer instead of comment because I have some code to paste. I took a swing at a dead simple object to assist with my running mean and came up with the following:
class RollingMean
{
int _pos;
int _count;
double[] _buffer;
public RollingMean(int size)
{
_buffer = new double[size];
_pos = 0;
_count = 0;
}
public RollingMean(int size, double initialValue)
: this(size)
{
// Believe it or not there doesn't seem to be a better(performance) way...
for (int i = 0; i < size; i++)
{
_buffer[i] = initialValue;
}
_count = size;
}
public double Push(double value)
{
_buffer[_pos] = value;
_pos = (++_pos > _buffer.Length - 1) ? 0 : _pos;
_count = Math.Min(++_count, _buffer.Length);
return Mean;
}
public double Mean
{
get
{
return _buffer.Sum() / _count;
}
}
}
I'm reading 16 channels of data from a data acquisition system so I will just instantiate one of these for each channel and I think it will be cleaner than managing a multi-dimensional array or separate set of buffer/postition for each channel.
Here is sample usage for anyone interested:
static void Main(string[] args)
{
RollingMean mean = new RollingMean(10, 7);
mean.Push(3);
mean.Push(4);
mean.Push(5);
mean.Push(6);
mean.Push(7.125);
Console.WriteLine( mean.Mean );
Console.ReadLine();
}
I was going to make the RollingMean object a generic rather than lock into double but I couldn't find a generic constraint to limit the tpye numerical types. I moved on, gotta get back to work. Thanks for you help.