I'm trying to reverse engineer a calculation that was done on an old program but can't quite get it. I need a count of how many values are in the top 27%, middle 46%, and bottom 27%.
I have the following data sets with eleven values in each and what the program yields in regards to the percentages and the number of values that fall into those percentiles.
Upper 27%: 4, Middle 46%: 4, Lower 27%: 3
values: 8,9,10,11,11,11,11,12,12,12,13
Upper 27%: 5, Middle 46%: 4, Lower 27%: 2
values: 2,3,4,4,4,4,5,5,5,5,5
Upper 27%: 2, Middle 46%: 8, Lower 27%: 1
values: 2,4,4,4,4,4,4,4,4,5,5
Upper 27%: 2, Middle 46%: 6, Lower 27%: 3
values: 13,17,17,18,19,19,19,21,21,23,24
I have found formulas such as (n * p) where n is the number of values and p is the percentile but it doesn't seem to work across all of these data sets to give the same results. I'm a little lost and haven't found anything that produces the results here.
I have tested code that I have found on the internet but none have worked on the different data sets.
Code sample that I tried:
internal static double percentile(double[] sortedData, double p)
{
if (p >= 100.0d) return sortedData[sortedData.Length - 1];
double position = (double)(sortedData.Length + 1) * p / 100.0;
double leftNumber = 0.0d, rightNumber = 0.0d;
double n = p / 100.0d * (sortedData.Length - 1) + 1.0d;
if (position >= 1)
{
leftNumber = sortedData[(int)System.Math.Floor(n) - 1];
rightNumber = sortedData[(int)System.Math.Floor(n)];
}
else
{
leftNumber = sortedData[0]; // first data
rightNumber = sortedData[1]; // first data
}
if (leftNumber == rightNumber)
return leftNumber;
else
{
double part = n - System.Math.Floor(n);
return leftNumber + part * (rightNumber - leftNumber);
}
}
Is there a formula or a name for what I am trying to do? Am I on the right track with percentile ranks?
You're on the right path. This is indeed the percentile rank formula. My initial thought was to get the value at the 27th percentile (which looking at your code it looks like you started down this path as well) and figure out how many values were greater than or less than; but the values you provided don't support these numbers very well.
Therefore the approach I took was to calculate the percentile rank of each number and put it into a count if they matched the percentile you have above. This seems to be the approach they took.
Formula (check out this website for more info):
PR% = L + ( 0.5 x S ) / N
Where,
L = Number of below rank,
S = Number of same rank,
N = Total numbers.
Code:
var lower = 0;
var middle = 0;
var upper = 0;
// var values = new int[] { 8, 9, 10, 11, 11, 11, 11, 12, 12, 12, 13 };
// var values = new int[] { 2, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5 };
// var values = new int[] { 2, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5 };
var values = new int[] { 13, 17, 17, 18, 19, 19, 19, 21, 21, 23, 24 };
var n = values.Length;
foreach(var i in values)
{
var pr = ((values.Count(v => v < i) + (.5 * values.Count(v => v == i))) / n);
if (pr < .27)
lower += 1;
else if (pr > .73)
upper += 1;
else
middle += 1;
}
Console.WriteLine("Upper: " + upper);
Console.WriteLine("Middle: " + middle);
Console.WriteLine("Lower: " + lower);
Related
I have an array A with values: {10, 12, 6, 14, 7} and I have an array B with values: {1, 8, 2}
I have sorted the array B in an ascending order and then combined both the arrays in a new array C as shown in the following code -
static void Main()
{
int A[] = {10, 12, 6, 14, 7};
int B[] = {1, 8, 2};
Array.Sort(B);
var myList = new List<int>();
myList.AddRange(A);
myList.AddRange(B);
int[] C = myList.ToArray();
//need values in this order: 10, 1, 12, 2, 8, 6, 14, 7
}
Now I wanna sort the array C this way: 10, 1, 12, 2, 8, 6, 14, 7
The smaller values should be between the larger values, for ex: 1 is between 10 and 12, 2 is between 12 and 8, 6 is between 8 and 14, so on and so forth.
How can I do this in C#?
If recursion is needed, how can I add it to the code?
What I understood from your example is that you are trying to alternate between large and small values such that the small value is always smaller than the number to the left and the right. I wrote an algorithm below to do that however it does not yield the exact same results you requested. However I believe it does meet the requirement.
The straggling 7 is considered the next smallest number in the sequence but there is no number that follows it. Based on your example it appears that is allowed.
To Invoke
int[] A = { 10, 12, 6, 14, 7 };
int[] B = { 1, 8, 2 };
var result = Sort(A, B);
Sort Method
public static int[] Sort(int[] A, int[] B)
{
var result = new int[A.Length + B.Length];
var resultIndex = 0;
Array.Sort(A);
Array.Sort(B);
//'Pointer' for lower index, higher index
var aLeft = 0;
var aRight = A.Length-1;
var bLeft = 0;
var bRight = B.Length - 1;
//When Items remain in both arrays
while (aRight >= aLeft && bRight >= bLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
{
if (A[aLeft] < B[bLeft])
result[resultIndex++] = A[aLeft++];
else
result[resultIndex++] = B[bLeft++];
}
//Add largest
else
{
if (A[aRight] > B[bRight])
result[resultIndex++] = A[aRight--];
else
result[resultIndex++] = B[bRight--];
}
}
//When items only in array A
while (aRight >= aLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
result[resultIndex++] = A[aLeft++];
//Add largest
else
result[resultIndex++] = A[aRight--];
}
//When items remain only in B
while (bRight >= bLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
result[resultIndex++] = B[bLeft++];
//Add largest
else
result[resultIndex++] = B[bRight--];
}
return result;
}
Result
[14, 1, 12, 2, 10, 6, 8, 7]
I am tasked to transform an Excel VBA to a web-based application. I am using Web Forms. I am stuck with a long Excel formula but I have converted half of the long formula into C#.
Here is the Excel formula:
IF(AND(D7="u", H7/F7>1), 0, INDEX(Scoring!$O$8:$O$10, SUMPRODUCT(--(E28 <= Scoring!$N8:$N10),--(E28 >= Scoring!$N8:$N10), ROW(INDIRECT("'Scoring'!$M1:$M3"))))
While here is my progress on the C# method. I need help on the ELSE part:
IF (variable = "u" && ((CurrentValue / AcceptedValue) > 1)){
return 0;
ELSE {
// the INDEX clause on the Excel Formula
}
O8 - O10 values are {2, 1, 0}
N8 - N10 values are {1, 1.5, 9999999999}
E28 is 0
I have also got the result of the remainder of the formula piece by piece. I just need guidance on how to put it in C#.
=INDEX(Scoring!$O$8:$O$10, SUMPRODUCT({1,1,1}, {0,0,0}, 1))
The double minus(--) made it return 0/1 instead of true/false. ROW(INDIRECT($M1-$M3)) is equivalent to 1.
I could use some help on transforming the Excel formula into C# code.
Here is some C# code to replicate this part of your formula:
INDEX(Scoring!$O$8:$O$10, SUMPRODUCT(--(E28 <= Scoring!$N8:$N10),--(E28 >= Scoring!$N8:$N10), ROW(INDIRECT("'Scoring'!$M1:$M3")))
In the code I've had to assign the array {1, 1, 1} for ROW(INDIRECT("'Scoring'!$M1:$M3")). There is some ambiguity in your question around the action of SUMPRODUCT. According to support.office.com
Multiplies corresponding components in the given arrays, and returns the sum of those products.
But some of your detail in the question makes me think you are thinking that each array get summed up and then those results get multiplied together. Anyway, check out the comments in the code below to follow the logic:
// inputs
double[] o8o10 = new double[] { 2, 1, 0 }; // Scoring!$O$8:$O$10
double[] n8n10 = new double[] { 1, 1.5, 9999999999 }; // Scoring!$N8:$N10
double e28 = 0; // E28
// entries to SUMPRODUCT
List<int> test1 = new List<int>();
List<int> test2 = new List<int>();
Array.ForEach(n8n10, x => { test1.Add((e28 <= x) ? 0 : 1); });
Array.ForEach(n8n10, x => { test2.Add((e28 >= x) ? 0 : 1); });
// ROW(INDIRECT("'Scoring'!$M1:$M3")) should be an array !
List<int> test3 = new List<int> { 1, 1, 1 };
// evalue SUMPRODUCT
int sumProductResult = 0;
for (var i=0; i<test1.Count; i++)
{
sumProductResult += test1[i] * test2[i] * test3[i];
}
// evalute INDEX
double indexResult = 0;
indexResult = o8o10[sumProductResult];
// output
Console.WriteLine(indexResult);
Console.ReadKey();
The output for me is 2 because that is the 0th element of the o8o10 array. We get 0 for the array index because
=SUMPRODUCT({1, 1, 1}, {0, 0, 0}, {1, 1, 1})
resolves to:
=SUM(1*0*1, 1*0*1, 1*0*1}
Which gives 0.
HTH
ROW(INDIRECT("'Scoring'!$M1:$M3")) actually evaluates to {1; 2; 3} and
--(E28 <= Scoring!$N8:$N10),--(E28 >= Scoring!$N8:$N10) is --(E28 = Scoring!$N8:$N10)
so the SUMPRODUCT formula is just:
(E28 = Scoring!$N8) * 1 + (E28 = Scoring!$N9) * 2 + (E28 = Scoring!$N10) * 3
and in C#:
double[] n8n10 = { 1, 2, 3 }; double e28 = 2;
double sumProduct = n8n10.Select((d, i) d == e28 ? i + 1 : 0).Sum();
But! because Scoring!$O$8:$O$10 is only 3 cells and the SUMPRODUCT can in theory result in more than 3, the actual aim of the INDEX SUMPRODUCT part seems to be something like this:
double[] o8o10 = { 4, 5, 6 }, n8n10 = { 1, 2, 3 };
double e28 = 2, result = o8o10[0]; // INDEX(array, 0) results in array
if (n8n10[1] == e28) result = o8o10[1];
else if (n8n10[2] == e28) result = o8o10[2];
I want to find how many values, in an array, are in sequence without sorting.
For Instance, if I have.
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 9 } //0, 1, 2, 3, 4, 5, 6 are in sequence
int value = HighestSequence(arr);
//value prints 7
int[] arr = new int[] { 0, 4, 1, 2, 3, 4, 7, 9 } //1, 2, 3, 4 are in sequence
int value = HighestSequence(arr);
//value prints 4
int[] arr = new int[] { 0, 1, 2 } //0, 1, 2 is in sequence
int value = HighestSequence(arr);
//value prints 3
You don't specify what should happen if there is more than one subsequence in order, but I've assumed there will be only one.
Try this:
int length = 1;
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 9 }; //0, 1, 2, 3, 4, 5, 6 are in sequence
//value prints 7
List<int> temp = arr.Zip(arr.Skip(1), (i1, i2) => length += (i2 - i1 == 1 ? 1 : 0)).ToList();
Length will contain the number of integers in sequence where arr[n] == arr[n+1] - 1
Cheers
EDIT:
In the case where there is more than one subsequence that is ordered such that arr[n] == arr[n+1] - 1, we'd need to decide how to handle it.
One way would be to reset the length when we find a value that doesn't meet the criteria:
arr = new int[] { 0, 1, 2, 5, 4, 5, 6, 9 }; //Possible bug ?
length = 1;
temp = arr.Zip(arr.Skip(1), (i1, i2) =>
{
if(i2 - i1 == 1)
{
length++;
}
else
{
length = 1;
}
return i1;
}).ToList();
But then this will not consider the "longest" subsequence, it will return the length of the "last" subsequence in the sequence.
The OP should specify what action he wants in such cases.
EDIT #2:
If we want to have the longest subsequence, then this could be used:
arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 5, 4, 5, 6, 7, 9 }; //Possible bug ?
length = 1;
int longest = length;
temp = arr.Zip(arr.Skip(1), (i1, i2) =>
{
if (i2 - i1 == 1)
{
if (++length > longest)
longest = length;
}
else
{
length = 1;
}
return i1;
}).ToList();
Caching the longest ordered subsequence length. Then use longest instead of length as the result.
EDIT #3:
Edits #1 & 2 should now contain the appropriate solution. I was obviously trying to come up with a solution to a comment from a user too quickly and I didn't realize that the current code in my VS solution was different than the code I posted here.
It is to be mentioned that the OP didn't have those additional constraints, and that I did mention right from the get go that my solution didn't address those additional constraints.
Nonetheless, it was an interesting problem to solve ;-)
Cheers
Try this out. I got the results of (7,4,3). Although Peter is correct about StackOverflow you should give your attempt and say your issue not just ask for an answer. I only provided it because it was a neat challenge.
var set1 = new [] { 0, 1, 2, 3, 4, 5, 6, 9 };
var result1 = HighestSequence(set1);
var set2 = new[] { 0, 4, 1, 2, 3, 4, 7, 9 };
var result2 = HighestSequence(set2);
var set3 = new [] { 0, 1, 2 };
var result3 = HighestSequence(set3);
public int HighestSequence(int[] values)
{
IList<int> sequenceCounts = new List<int>();
var currentSequence = 0;
for (var i = 0; i < values.Length; i++)
{
if (i == (values.Length - 1)) //End edge case
{
if (values[i] - values[i - 1] == 1)
{
currentSequence++;
sequenceCounts.Add(currentSequence);
}
}
else if ((values[i] + 1) == values[i + 1])
{
currentSequence++;
}
else
{
currentSequence++;
sequenceCounts.Add(currentSequence);
currentSequence = 0;
continue;
}
sequenceCounts.Add(currentSequence);
}
return sequenceCounts.Max();
}
I have been searching for some time now for any answers on how to do this.
What I am trying to do is, take an array of numbers, e.g. {1, 3, 5, 6, 8, 7, 6 ,5, 3, 1} (but it will use user input) and find the duplicates of these numbers that are mirrored and return how many indexes are involved in just one instance of said array.
I know the basics of C# but can't grasp this task. No, this is not homework. This is my own project to further my knowledge.
I am not currently around the code I have for parts of this, but would really appreciate any help/advice anyone could give me.
int[] array = {1, 3, 5, 6, 8, 7, 6 ,5, 3, 1};
//holds left index of mirrored pair, you can easily find the right one
var mirroredIndexes = new List<int>();
var length = array.Length;
for (int i = 0; i < length / 2; i++)
{
if(array[i] == array[length - i - 1])
mirroredIndexes.Add(i);
}
mirroredIndexes.ForEach(Console.WriteLine);
Console.WriteLine ("total of {0} mirrored pairs ({1})",
mirroredIndexes.Count,
string.Join(", ", mirroredIndexes.Select(i => array[i])));
prints next indexes:
0
1
2
3
total of 4 mirrored pairs (1, 3, 5, 6)
I think this is what you are after. This will return a list of matching indices.
Eg. first == last, second == second to last, third == third to last
var matches = new List<Tuple<int, int>>();
var array = new [] { 0, 1, 2, 3, 4, 5, 3, 2, 1, 0 };
if (array.Length % 2 != 0)
throw new Exception("Array must have an even amount of elements");
for (int i = 0; i < array.Length / 2; i++)
{
if (array[i] == array[array.Length - 1 - i])
{
matches.Add(new Tuple<int, int>(i, array.Length - 1 - i));
}
}
var firstMatchingIndex1 = matches[0].Item1;
// This will be 0
var firstMatchingIndex2 = matches[0].Item2;
// This will be 9
You could go further, using a custom class, and capture the actual value that matched (eg. index1 is 1, index2 is 8 and the value was 1.
Suppose I have this number list:
List<int> = new List<int>(){3,5,8,11,12,13,14,21}
Suppose that I want to get the closest number that is less than 11, it would be 8
Suppose that I want to get the closest number that is greater than 13 that would be 14.
The numbers in list can't be duplicated and are always ordered. How can I write Linq for this?
with Linq assuming that the list is ordered I would do it like this:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var lessThan11 = l.TakeWhile(p => p < 11).Last();
var greaterThan13 = l.SkipWhile(p => p <= 13).First();
EDIT:
As I have received negative feedback about this answer and for the sake of people that may see this answer and while it's accepted don't go further, I explored the other comments regarding BinarySearch and decided to add the second option in here (with some minor change).
This is the not sufficient way presented somewhere else:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = ~l.BinarySearch(10) -1;
var value = l[indexLessThan11];
Now the code above doesn't cope with the fact that the value 10 might actually be in the list (in which case one shouldn't invert the index)! so the good way is to do it:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = l.BinarySearch(10);
if (indexLessThan11 < 0) // the value 10 wasn't found
{
indexLessThan11 = ~indexLessThan11;
indexLessThan11 -= 1;
}
var value = l[indexLessThan11];
I simply want to note that:
l.BinarySearch(11) == 3
//and
l.BinarySearch(10) == -4;
Use Array.BinarySearch - no need for LINQ or visiting on average half the elements to find your target.
There are also a variety of SortedXXX classes that may be suitable for what you're doing [that will have such efficient O(log N) searches built-in]
You can do this using a binary search. If your searching for 11, well obviously you'll get the index your after. If you search for 10 and use the bitwise complement of the result, you'll get the closest match.
List<int> list = new List<int>(){3,5,8,11,12,13,14,21};
list.Sort();
int index = list.BinarySearch(10);
int found = (~index)-1;
Console.WriteLine (list[found]); // Outputs 8
The same goes searching in the other direction
int index = list.BinarySearch(15);
Console.WriteLine("Closest match : " + list[+~index]); // Outputs 21
Binary searches are also extremely fast.
closest number below 11:
int someNumber = 11;
List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };
var intermediate = from i in list
where i < someNumber
orderby i descending
select i;
var result = intermediate.FirstOrDefault();
closest number above 13:
int someNumber = 13;
List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };
var intermediate = from i in list
where i > someNumber
orderby i
select i;
var result = intermediate.FirstOrDefault();
This is my answer
List<int> myList = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
int n = 11;
int? smallerNumberCloseToInput = (from n1 in myList
where n1 < n
orderby n1 descending
select n1).First();
int? largerNumberCloseToInput = (from n1 in myList
where n1 > n
orderby n1 ascending
select n1).First();
var list = new List<int> {14,2,13,11,5,8,21,12,3};
var tested = 11;
var closestGreater = list.OrderBy(n => n)
.FirstOrDefault(n => tested < n); // = 12
var closestLess = list.OrderByDescending(n => n)
.FirstOrDefault(n => tested > n); // = 8
if (closestGreater == 0)
System.Diagnostics.Debug.WriteLine(
string.Format("No number greater then {0} exists in the list", tested));
if (closestLess == 0)
System.Diagnostics.Debug.WriteLine(
string.Format("No number smaler then {0} exists in the list", tested));
Here is my way hope this helps somebody!
List<float> list = new List<float> { 4.0f, 5.0f, 6.0f, 10.0f, 4.5f, 4.0f, 5.0f, 6.0f, 10.0f, 4.5f, 4.0f, 5.0f, 6.0f, 10.0f };
float num = 4.7f;
float closestAbove = list.Aggregate((x , y) => (x < num ? y : y < num ? x : (Math.Abs(x - num)) < Math.Abs(y - num) ? x : y));
float closestBelow = list.Aggregate((x , y) => (x > num ? y : y > num ? x : (Math.Abs(x - num)) < Math.Abs(y - num) ? x : y));
Console.WriteLine(closestAbove);
Console.WriteLine(closestBelow);
This means you dont have to order the list
Credit: addapted from here: How to get the closest number from a List<int> with LINQ?
The Expanded Code
float closestAboveExplained = list.Aggregate((closestAbove , next) => {
if(next < num){
return closestAbove;
}
if(closestAbove < num){
return next;
}
else{
if(Math.Abs(closestAbove - num) < Math.Abs(next - num)){
return closestAbove;
}
}
return next;
});
You can use a query for this such as:
List<int> numbers = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
List<int> output = (from n in numbers
where n > 13 // or whatever
orderby n ascending //or descending
select n).ToList();