Lets say i have a list of doubles:
0.0015
0.0016
0.0017
0.0019
0.0021
0.0022
0.0029
0.0030
0.0033
0.0036
And there's obviously a large difference in 0.0022 and 0.0029 compared to the rest, but is there a way i can make my C# program to be able to notice this difference within a sorted list W/O using a static threshold value. Because these data that i receive, the difference might not always be 0.0007 difference. So i would prefer if my program is able to be 'smart' enough to identify these 'large' differences and separate this list into multiple lists.
if i have understood your question correctly here goes. you may need to fill in a few gaps but you will get the drift with the below example:
List<double> doubleList = new List<double>{
0.0015,
0.0016,
0.0017,
0.0019,
0.0021,
0.0022,
0.0029,
0.0030,
0.0033,
0.0036
};
double averageDistance = 0.0;
double totals = 0.0;
double distance = 0.0;
for (int x = 0; x < (doubleList.Count - 1); x++)
{
distance = doubleList[x] - doubleList[x + 1];
totals += Math.Abs(distance);
}
averageDistance = totals / doubleList.Count;
// check to see if any distance between numbers is more than the average in the list
for (int x = 0; x < (doubleList.Count - 1); x++)
{
distance = doubleList[x] - doubleList[x + 1];
if (distance > averageDistance)
{
// this is where you have a gap that you want to do some split (etc)
}
}
Calculate the mean average (http://en.wikipedia.org/wiki/Arithmetic_mean) and the standard deviation (http://en.wikipedia.org/wiki/Standard_deviation). Use these to determine the values that fall outside of 'n' standard deviations.
Another approach would be to calculate all the differences between consecutive values, sort these (descending) and assume the top 'm' % of these difference values represent the largest changes.
Related
This question already has answers here:
Generating a list of random numbers, summing to 1
(12 answers)
Closed 2 years ago.
I am making a space game with planets that are randomly generated and I need their atmospheres to be made up of random amounts of different elements. So the thing is that I want the elements to be percentages of the complete atmosphere, an example: oxygen = 30, nitrogen = 20, carbondioxide = 50, hydrogen = 0. All these values should be completely randomized and the sum of them all has to be 100.
I basically want to fill a container to the top with random amounts of set elements, but I don't know how to randomize all of the variables and end up with a fixed sum.
This is my first time submitting anything to StackOverflow so please let me know if there is anything I need to clarify, I've been stuck on this issue for so long without finding any answers so I would appreciate any help, thanks :)
(I am using c# in unity in case that makes a difference)
Well, you could think of it from the other perspective, and generate random values for each element, then use their total as 100%.
For instance...
var rnd = New Random()
ChecmicalsInAir = 9;
Hydrogen = rnd.Next();
Oxygen = rnd.Next();
...
TotalAtmos = (Hydrogen + Oxygen + ...);
Yes - as pointed out by canton7, below:
Dividing the chemical by TotalAtmos will give you the percentage of atmosphere.
Just to add a little more to this answer, you may also wish to use a Dictionary to store the information, rather than simple variables; that way you can include different gases in the atmosphere, as not all planets may have oxygen or nitrogen, this could add different bonuses or penalties, but remains a straightforward process for calculating percentages.
Questions like "how would you design this..." are better suited for Game Development. Those questions tend to get downvoted here a lot.
Here's one way you could do it.
int elementCount = 3; // set to the number of elements you have
List<float> elementPercents = new List<float>();
// Assign an initial value between 0 and 1 to each element, and set totalWeight
// to the sum of all those values. Note that this lets you have 0 for an element.
// If you don't want 0 for an element, adjust the Random.Range
float totalWeight = 0;
for (int i = 0; i < elementCount; i++)
{
elementPercents.Add(UnityEngine.Random.Range(0f, 1f));
totalWeight += elementPercents[i];
}
// Set the percent of each element to its proportion of the total weight.
// For example, if Oxygen = 0.1 and Hydrogen = 0.2 and Nitrogen = 0.3 from the above statement,
// then Oxygen's percent = 0.1 / (0.1 + 0.2 + 0.3) = 0.167
for (int i = 0; i < elementCount; i++)
{
elementPercents[i] /= totalWeight;
}
// Assign the percents to each element according to your requirements, for example
float hydrogen = elementPercents[0];
float nitrogen = elementPercents[1];
float oxygen = elementPercents[2];
I have two lists of numbers, the first list has 365 numbers and the other one has 8760.
I want to loop the first list first and get the value. Then inside the first loop, I want to loop the second list to get the 24 number each time.
For the next iterative, it will skip the first 24 and get the next 24.
The problem is the "countelev" seems to not change and stay in ''24'' for every time when I print it. It supposes to be changed to 48, 72, 96....
This is my code:
foreach (var dec in declinationangle)
{
double declination = dec;
double elev = Degreetoradian(declination);
double lati = Degreetoradian(latitude);
// Solar elevation angle, expressed as α, is the angular height of the
//sun in the sky measured from the horizontal 0° at sunrise and 90° when
//the sun is right overhead.
//α = sin−1 (sin δ sin φ + cos δ cos φ cos τ)
int countelev = 0;
foreach (var hra in Solarhourangle.Skip(countelev).Take(24))
{
double hras = Degreetoradian(hra);
double elev1 = Math.Sin(elev) * Math.Sin(lati);
double elev2 = Math.Cos(elev) * Math.Cos(lati) * Math.Cos(hras);
double slav = Math.Asin(elev1 + elev2);
double sla = Radiantodegree(slav);
solarelevationangle.Add(sla);
}
countelev += 24;
TaskDialog.Show("countelev", countelev.ToString());
}
int countelev = 0;
This statement needs to be the first statement of the block that you have pasted. Means the statement needs to be outside the nested foreach statements.
It's considerably simpler with for instead of foreach. You only need one loop, with an index that iterates over the larger array. It can select the correct element from the smaller array by dividing the index by 24 and throwing away the remainder (which, conveniently, is how integer division in c# works).
Here's another way to think of it. Instead of generating elements from two smaller lists, you are populating elements in the target list from two other lists-- since there is only one target list, you only need one loop.
for (var i = 0; i< Solarhourangle.Count; i++)
{
hra = Solarhourangle[i];
dec = declinationangle[i/24];
double elev = Degreetoradian(declination);
double lati = Degreetoradian(latitude);
double hras = Degreetoradian(hra);
double elev1 = Math.Sin(elev) * Math.Sin(lati);
double elev2 = Math.Cos(elev) * Math.Cos(lati) * Math.Cos(hras);
double slav = Math.Asin(elev1 + elev2);
double sla = Radiantodegree(slav);
solarelevationangle.Add(sla);
}
I need to calculate distances between every pair of points in an array and only want to do that once per pair. Is what I've come up with efficient enough or is there a better way? Here's an example, along with a visual to explain what I'm trying to obtain:
e.g., first get segments A-B, A-C, A-D; then B-C, B-D; and finally, C-D. In other words, we want A-B in our new array, but not B-A since it would be a duplication.
var pointsArray = new Point[4];
pointsArray[0] = new Point(0, 0);
pointsArray[1] = new Point(10, 0);
pointsArray[2] = new Point(10, 10);
pointsArray[3] = new Point(0, 10);
// using (n * (n-1)) / 2 to determine array size
int distArraySize = (pointsArray.Length*(pointsArray.Length - 1))/2;
var distanceArray = new double[distArraySize];
int distanceArrayIndex = 0;
// Loop through points and get distances, never using same point pair twice
for (int currentPointIndex = 0; currentPointIndex < pointsArray.Length - 1; currentPointIndex++)
{
for (int otherPointIndex = currentPointIndex + 1;
otherPointIndex < pointsArray.Length;
otherPointIndex++)
{
double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X;
double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y;
double distance = Math.Sqrt(Math.Pow(xDistance, 2) + Math.Pow(yDistance, 2));
// Add distance to distanceArray
distanceArray[distanceArrayIndex] = distance;
distanceArrayIndex++;
}
}
Since this will be used with many thousands of points, I'm thinking a precisely dimensioned array would be more efficient than using any sort of IEnumerable.
If you have n points, the set of all pairs of points contains n * (n-1) / 2 elements. That's the number of operations you are doing. The only change I would do is using Parallel.ForEach() to do the operations in parallel.
Something like this (needs debugging)
int distArraySize = (pointsArray.Length * (pointsArray.Length - 1)) / 2;
var distanceArray = new double[distArraySize];
int numPoints = pointsArray.Length;
Parallel.ForEach<int>(Enumerable.Range(0, numPoints - 2),
currentPointIndex =>
{
Parallel.ForEach<int>(Enumerable.Range(currentPointIndex + 1, numPoints - 2),
otherPointIndex =>
{
double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X;
double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y;
double distance = Math.Sqrt(xDistance * xDistance + yDistance * yDistance);
int distanceArrayIndex = currentPointIndex * numPoints - (currentPointIndex * (currentPointIndex + 1) / 2) + otherPointIndex - 1;
distanceArray[distanceArrayIndex] = distance;
});
});
Looks good to me, but don't you have a bug?
Each of the inner iterations will overwrite the previous one almost completely, except for its first position. Won't it?
That is, in distanceArray[otherPointIndex] otherPointIndex gets values from currentPointIndex + 1 to pointsArray.Length - 1.
In your example, this will range on [0-3] instead of [0-6].
I've had to perform operations like this in the past, and I think your immediate reaction to high number crunch operations is "there must be a faster or more efficient way to do this".
The only other even remotely workable solution I can think of would be to hash the pair and place this hash in a HashSet, then check the HashSet before doing the distance calculation. However, this will likely ultimately work out worse for performance.
You're solution is good. As j0aqu1n points out, you're probably going to have to crunch the numbers one way or another, and in this case you aren't ever performing the same calculation twice.
It will be interesting to see if there are any other solutions to this.
I think, it's a bit faster to use xDistance*xDistance instead of Math.Pow(xDistance, 2).
Apart from this, if you really always need to calculate all distances, there is not much room for improvement.
If, OTOH, you sometimes don't need to calculate all, you could calculate the distances lazily when needed.
I want to create an array containing values from 0 to 1 with interval of 0.1. I can use:
float[] myArray = new float[10];
float increment = 0.1;
for(i = 0; i < 10; i++)
{
myArray[i] = increment;
increment += 0.1;
}
I was wondering whether there is a function like Enumerable.Range that permits to specify also the increment interval.
An interesting fact is that every answer posted so far has fixed the bug in your proposed code, but only one has called out that they've done so.
Binary floating point numbers have representation error when dealing with any quantity that is not a fraction of an exact power of two. ("3.0/4.0" is a representable fraction because the bottom is a power of two; "1.0/10.0" is not.)
Therefore, when you say:
for(i = 0; i < 10; i++)
{
myArray[i] = increment;
increment += 0.1;
}
You are not actually incrementing "increment" by 1.0/10.0. You are incrementing it by the closest representable fraction that has an exact power of two on the bottom. So in fact this is equivalent to:
for(i = 0; i < 10; i++)
{
myArray[i] = increment;
increment += (exactly_one_tenth + small_representation_error);
}
So, what is the value of the tenth increment? Clearly it is 10 * (exactly_one_tenth + small_representation_error) which is obviously equal to exactly_one + 10 * small_representation_error. You have multiplied the size of the representation error by ten.
Any time you repeatedly add together two floating point numbers, each subsequent addition increases the total representation error of the sum slightly and that adds up, literally, to a potentially large error. In some cases where you are summing thousands or millions of small numbers the error can become far larger than the actual total.
The far better solution is to do what everyone else has done. Recompute the fraction from integers every time. That way each result gets its own small representation error; it does not accumulate the representation errors of previously computed results.
Ugly, but...
Enumerable.Range(0,10).Select(i => i/10.0).ToArray();
No, there's no enumerable range that allows you to do that, but you could always divide by 10:
foreach (int i in Enumerable.Range(0, 10))
array[i] = (i + 1) / 10.0f
Note that this avoids the error that will accumulate if you repeatedly sum 0.1f. For example, if you sum the 10 elements in the myArray in your sample code, you get a value that's closer to 5.50000048 than 5.5.
Here is one way:
Enumerable.Range(1,10).Select(i => i /10.0)
Well you could use this:
Enumerable.Range(1,10).Select(x => x / 10.0).ToArray()
Not sure if that's better though.
This is probably very simple, but my attempts (guided by Intellisense and MSDN) have all been off the mark.
If I have a class which contains 3 double, how can I get the average of a list of these?
class DataPoint
{
public int time;
public int X;
public int Y;
public int Z;
// Constructor omitted
}
class Main
{
List<DataPoint> points = new List<DataPoint>();
// Populate list
DataPoint averagePoint = points.Average(someMagicHere);
}
I want averagePoint to contain time, x, y & z values that are the average of these properties of the elements that make up the list. How do I do this? The bit I'm struggling with is (I think) someMagicHere, but I could be using completely the wrong approach to begin with.
The question is not entirely clear, but it sounds like what you want is a new point P where P.X is the average of all the X coordinates of the points in the list, and so on, yes?
The general way to solve a problem like this is to break it down:
First transform the list of points into four lists of integers.
var times = from p in points select p.Time;
var xs = from p in points select p.X;
... and so on ..
Or, if you prefer this notation:
var times = points.Select(p=>p.Time);
Now you can average those:
double averageTime = times.Average();
double averageX = xs.Average();
... and so on ...
and now you have your four values -- as doubles -- that you can use to construct the average point. Of course you'll have to convert the doubles to integers, using whatever rounding you prefer.
However, there is a special version of "Average" which combines the Select and the Average into one operation. You can just say
double averageTime = points.Average(p=>p.Time);
and do it in one step for both the projection and the average.
The down side of this approach, as some have noted, is that the sequence is enumerated four times. Which is probably not a big deal, since it is an in-memory list, but might be more of a big deal if it were an expensive database query.
Another approach would be to define the addition operator on your DataPoint class (if in general it makes sense to sum two points, which it might not). Once you have an addition operator, making the sum of all the points is straightforward.
Whether you define an addition operator or not, you can use Aggregate to compute the sum of all the Points, and then divide the four fields of the sum by the number of points.
DataPoint sum = points.Aggregate(
new DataPoint(0, 0, 0, 0),
(agg, point)=> new DataPoint(agg.time + point.time, agg.x + point.x, ... ));
or, if you have the operator, simply:
DataPoint sum = points.Aggregate(
new DataPoint(0, 0, 0, 0),
(agg, point)=> agg + point);
And now you have the sum, so computing the average is straightforward.
static class DataPointExtensions
{
public static DataPoint Average (this IEnumerable<DataPoint> points)
{
int sumX=0, sumY=0, sumZ=0, count=0;
foreach (var pt in points)
{
sumX += pt.X;
sumY += pt.Y;
sumZ += pt.Z;
count++;
}
// also calc average time?
if (count == 0)
return new DataPoint ();
return new DataPoint {X=sumX/count,Y=sumY/count,Z=sumZ/count};
}
}
Well, it would seem that you need to take average of each projection in turn
DataPoint averagePoint = new DataPoint{
X = (int)Points.Average(p => X),
Y = (int)Points.Average(p => P.Y),
Z = (int)Points.Average(p => p.Z),
time = (int)Points.Average(p => p.time)
};
I cast to int, because your types are int, although they probably should be double, or converted to your integer lattice more intelligently.
Another way is using running averages. It's slower than Lamperts, and assumes that the backing datatype for the DataPoint is double. But if the set of Points is HUGE, and points are ordered randomly it has a nice Monte-Carlo convergence. It also enumarates the List only once.:
var averagePoint = Points.First();
foreach(var point in Points.Skip(1).Select((p,i) => new{ Point = p, Index = i})){
averagePoint.X = (point.Index * averagePoint.X + p.Point.X)/(point.Index + 1);
averagePoint.Y = (point.Index * averagePoint.Y + p.Point.Y)/(point.Index + 1);
averagePoint.Z = (point.Index * averagePoint.Z + p.Point.Z)/(point.Index + 1);
}