Algorithm for Fogbugz pricing scheme - c#

I'm looking for an algorithm to calculate total cost of licenses purchased based on the "FogBugz for your server" pricing scheme (http://www.fogcreek.com/FogBugz/PriceList.html).
Fogbugz pricing is:
1 License $299
5 License Pack $999
10 License Pack $1,899
20 License Pack $3,499
50 License Pack $7,999
If you ask a quote for let's say 136 licenses they calculate it as $22,694.
How can I do this in C# or LINQ?
Any help will be appreciated.

int licenses = 136;
int sum = 0;
while (licenses > 0)
{
if (licenses >= 50) { sum += 7999; licenses -= 50; }
else if (licenses >= 20) { sum += 3499; licenses -= 20; }
else if (licenses >= 10) { sum += 1899; licenses -= 10; }
else if (licenses >= 5) { sum += 999; licenses -= 5; }
else { sum += 299; licenses -= 1; }
}
// sum == 22694
or
int licenses = 136;
int sum = 7999 * Math.DivRem(licenses, 50, out licenses)
+ 3499 * Math.DivRem(licenses, 20, out licenses)
+ 1899 * Math.DivRem(licenses, 10, out licenses)
+ 999 * Math.DivRem(licenses, 5, out licenses)
+ 299 * licenses;
// sum == 22694

The accepted answer, whilst an elegant piece of code from a programmer's point of view, does not give the best possible price for the customer and therefore might not be an elegant solution from the customer's point of view. For example when n = 4, the accepted answer gives $1196, but a customer would obviously prefer to choose the 5 license pack and pay just $999 instead.
It is possible to construct an algorithm which can calculate the minimum price possible that the customer can pay to purchase their required number of licenses. One way of doing this is to use dynamic programming. I think something like this might do the trick:
int calculatePrice(int n, Dictionary<int, int> prices)
{
int[] best = new int[n + prices.Keys.Max()];
for (int i = 1; i < best.Length; ++i)
{
best[i] = int.MaxValue;
foreach (int amount in prices.Keys.Where(x => x <= i))
{
best[i] = Math.Min(best[i],
best[i - amount] + prices[amount]);
}
}
return best.Skip(n).Min();
}
void Run()
{
Dictionary<int, int> prices = new Dictionary<int, int> {
{ 1, 299 },
{ 5, 999 },
{ 10, 1899 },
{ 20, 3499 },
{ 50, 7999 }
};
Console.WriteLine(calculatePrice(136, prices));
Console.WriteLine(calculatePrice(4, prices));
}
Output:
22694
999
Update Producing a breakdown is a little more complicated, but I definitely think it will be beneficial for your customers. You could do it something like this (assuming printing to the console, although a real program would probably output to a web page):
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static Dictionary<int, int> prices = new Dictionary<int, int> {
{ 1, 299 },
{ 5, 999 },
{ 10, 1899 },
{ 20, 3499 },
{ 50, 7999 }
};
class Bundle
{
public int Price;
public Dictionary<int, int> Licenses;
}
Bundle getBestBundle(int n, Dictionary<int, int> prices)
{
Bundle[] best = new Bundle[n + prices.Keys.Max()];
best[0] = new Bundle
{
Price = 0,
Licenses = new Dictionary<int, int>()
};
for (int i = 1; i < best.Length; ++i)
{
best[i] = null;
foreach (int amount in prices.Keys.Where(x => x <= i))
{
Bundle bundle = new Bundle
{
Price = best[i - amount].Price + prices[amount],
Licenses = new Dictionary<int,int>(best[i - amount].Licenses)
};
int count = 0;
bundle.Licenses.TryGetValue(amount, out count);
bundle.Licenses[amount] = count + 1;
if (best[i] == null || best[i].Price > bundle.Price)
{
best[i] = bundle;
}
}
}
return best.Skip(n).OrderBy(x => x.Price).First();
}
void printBreakdown(Bundle bundle)
{
foreach (var kvp in bundle.Licenses) {
Console.WriteLine("{0,2} * {1,2} {2,-5} # ${3,4} = ${4,6}",
kvp.Value,
kvp.Key,
kvp.Key == 1 ? "user" : "users",
prices[kvp.Key],
kvp.Value * prices[kvp.Key]);
}
int totalUsers = bundle.Licenses.Sum(kvp => kvp.Key * kvp.Value);
Console.WriteLine("-------------------------------");
Console.WriteLine("{0,7} {1,-5} ${2,6}",
totalUsers,
totalUsers == 1 ? "user" : "users",
bundle.Price);
}
void Run()
{
Console.WriteLine("n = 136");
Console.WriteLine();
printBreakdown(getBestBundle(136, prices));
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("n = 4");
Console.WriteLine();
printBreakdown(getBestBundle(4, prices));
}
static void Main(string[] args)
{
new Program().Run();
}
}
Output:
n = 136
2 * 50 users # $7999 = $ 15998
1 * 20 users # $3499 = $ 3499
1 * 10 users # $1899 = $ 1899
1 * 5 users # $ 999 = $ 999
1 * 1 user # $ 299 = $ 299
-------------------------------
136 users $ 22694
n = 4
1 * 5 users # $ 999 = $ 999
-------------------------------
5 users $ 999

Mark's solution is a great general solution, and definitely what you should go with (in case prices ever change.) This solution combines the simplicity of dtb's with the correctness of the Mark's:
int licenses = 136;
int sum = 7999 * Math.DivRem(licenses, 50, out licenses)
+ 7999 * Math.DivRem(licenses, 46, out licenses)
+ 3499 * Math.DivRem(licenses, 20, out licenses)
+ 1899 * Math.DivRem(licenses, 10, out licenses)
+ 999 * Math.DivRem(licenses, 5, out licenses)
+ 999 * Math.DivRem(licenses, 4, out licenses)
+ 299 * licenses;
It looks like the only edge cases are 5 is better than 4, and 50 is better than 46...49. Although, realistically, you should probably suggest 50 when someone looks for 45, since the extra 5 licenses only cost $2. So, maybe chnage 46 to 45 in the code.

Related

Find the least amount of intervals which cover highest range

I would like to ask for a hint how to approach in solving this task:
I have intervals ordered by min. value eg: ([1,5],[2,9],[6,7],[8,16],[11,15], [18,20]).
I should pick minimal amount of intervals, which cover the largest range.
So I should store these: ([1,5],[2,9],[8,16],[18,20]). Interval [6,7] is not stored, because it is covered by interval [2,9]. Interval [11,15] is not stored, because it is covered by [8,16].
How should I approach in solving this? Thank you:)
Linq approach
int[][] input = new[] { new[] { 1, 5 }, new[] { 2, 9 }, new[] { 6, 7 }, new[] { 8, 16 }, new[] { 11, 15 }, new[] { 18, 20 } };
int[][] result = input.Where((i1, x1) => !input.Where((i2, x2) => x1 != x2 && i2[0] <= i1[0] && i2[1] >= i1[1]).Any()).ToArray();
https://dotnetfiddle.net/x1xosT
Update: Thanks to #yuriy-faktorovich I've a added a <= and >= comparison instead < and >. Also removed the comparison with itselve.
It looks like all you need to do is keep track of the current highest range and only store numbers that are higher.
So the first highest number would be 5 so you store it, then add 9 and make it the highest number, then you reach 7 which is less than 9, so it's not stored, then you add 16 and make it the highest, 15 is less than 16, so skip it, and then finally add 20.
idk what language you're using, but the code would look something like.
foreach(var item in dataset)
{
if(item[1] > highest)
{
savedItems.Add(item);
highest = item[1];
}
}
I believe there could be local maximums, so I wrote the recursive function to look at different options
static List<(int lower,int higher)> Minimize(List<(int lower, int higher)> list, int i = 0)
{
//past last item
if (i >= list.Count) return list;
if (( i > 0 && list[i - 1].higher >= list[i].higher) ||
(i + 1 < list.Count && list[i + 1].lower == list[i].lower) ||
(i > 0 && i + 1 < list.Count && list[i + 1].lower - list[i - 1].higher <= 1))
{
var newList = list.ToList();
newList.RemoveAt(i);
var minimizedNewList = Minimize(newList);
var minimizedCurrentList = Minimize(list, i + 1);
return minimizedNewList.Count < minimizedCurrentList.Count ? minimizedNewList : minimizedCurrentList;
}
else return Minimize(list, i + 1);
}
You can test with the following
var testData = new[] {(1, 5), (2, 9), (6,7), (8, 16), (11, 15), (18, 20)};
var result = Minimize(testData.ToList());
foreach (var valueTuple in result)
{
WriteLine(valueTuple);
}
WriteLine("----------------------------");
testData = new[] { (1, 5), (5, 6), (6, 7) };
result = Minimize(testData.ToList());
foreach (var valueTuple in result)
{
WriteLine(valueTuple);
}
WriteLine("----------------------------");
testData = new[] { (1, 10), (5, 6) };
result = Minimize(testData.ToList());
foreach (var valueTuple in result)
{
WriteLine(valueTuple);
}
WriteLine("----------------------------");
testData = new[] { (1, 10), (1, 20) };
result = Minimize(testData.ToList());
foreach (var valueTuple in result)
{
WriteLine(valueTuple);
}
Here's a fiddle https://dotnetfiddle.net/EC5BrW

Take a group of numbers put them in 3 new groups evenly

To explain in more detail. I need to take a bunch of numbers and place them in classes/groups. Lets say I have 100 numbers. I need to divide that by the number of classes (n) where n = 3 and place them in three groups with 33, 33, 34 numbers respectively. or if (n) = 4 then it would be 4 classes of 25, 25, 25, 25. They also need to stay grouped from highest to lowest.
I have searched and saw a few things relating to LINQ to do this but I haven't wrapped my head around it.
I figured I could put all the numbers in a list, then find the total number in the index divide it by the number of classes to find out how many need to go into each class. My problem comes in is how to pull the numbers out of the list and place them in there respective groups while maintaining there grouping highest to lowest. Result desired for 3 classes with 15 numbers.
List<int> test = new List<int> { 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86 };
int total_indexes = test.Count + 1;
float classes = (total_indexes / 3);
Classes would equal 5 so it would look like this below
Class A:
100
99
98
97
96
Class B:
95
94
93
92
91
Class C:
90
89
88
87
86
Ok so I wrote this piece of code to give you the result you want:
public List<int[]> Do(int[] numbers, int groupCount)
{
numbers = numbers.OrderByDescending(x => x).ToArray();
var result = new List<int[]>();
var itemsCountInEachGroup = numbers.Length / groupCount;
var remainingCount = numbers.Length % groupCount;
var iterateCount = groupCount;
for (int i = 0; i < iterateCount; i++)
{
var skip = i * itemsCountInEachGroup;
//Last iterate
if (i == iterateCount - 1)
{
var n = numbers.Skip(skip).Take(itemsCountInEachGroup + remainingCount).ToArray();
result.Add(n);
}
else
{
var n = numbers.Skip(skip).Take(itemsCountInEachGroup).ToArray();
result.Add(n);
}
}
return result;
}
Example =>
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
var res = Do(numbers, 5);
This solution is probably not very optimized, and is likely to be improved.
int groupNb = 3, elementNb = 100;
//Populating elements with pseudo-random numbers for demonstration
Random r = new Random();
List<int> elements = new List<int>();
for (int i = 0; i < elementNb; i++)
elements.Add(r.Next(0, 100));
//The groups
List<int>[] groups = new List<int>[groupNb];
//Classifying elements in groups
int currentGroup = 0;
foreach (int value in elements.OrderByDescending(x => x))
{
if (groups[currentGroup] == null)
groups[currentGroup] = new List<int>();
groups[currentGroup].Add(value);
currentGroup = ++currentGroup % groupNb;
}
I did the answer with a PowerShell
open PowerShell ISE
and write the following script:
$Numbers = 100,94,91,90,89,85,84,81,79,74,74,70,95,92,83
$SortedNumbers = $Numbers | sort -Descending
$NumberofClasses = 3
$Countofnumbersinclase = $Numbers.Count / $NumberofClasses
$x = 0
$y = 0
For ($i = 0 ; $i -lt $NumberofClasses ;$i++){
$y = $i+$Countofnumbersinclase-1+$y
$Clasno = $i+1
Write-host "class No $Clasno is " $SortedNumbers[$X..$Y]
$x = $y+1
}
The result as following:
class No 1 is 100 95 94 92 91
class No 2 is 90 89 85 84 83
class No 3 is 81 79 74 74 70
I think exactly s you want and you can add any numbers or any no of classes and it will works
If all groups (with the only exception of the last one) should have equal number of items you can try Linq OrderBy followed by GroupBy:
Code:
using System.Linq;
...
private static List<T>[] Classify<T>(List<T> source, int count)
where T : IComparable<T> {
int size = source.Count / count;
return source
.OrderBy(item => item)
.Select((item, index) => new { item, index })
.GroupBy(pair => Math.Clamp(pair.index / size, 0, count - 1),
pair => pair.item)
.Select(group => group.ToList())
.ToArray();
}
If your C# version doesn't have Math.Clamp you can implement it as
private static int Clamp(int value, int min, int max) {
return value < min ? min :
value > max ? max :
value;
}
Demo:
// Let's split "count" items into "classes" classes
int count = 10;
int classes = 4;
List<int> demo = Enumerable
.Range(1, count)
.ToList();
var result = Classify(demo, classes);
string report = string.Join(Environment.NewLine, result
.Select(list => $"{list.First()} - {list.Last()} ({list.Count} items) : {string.Join(", ", list)}"));
Console.Write(report);
Outcome:
1 - 2 (2 items) : 1, 2
3 - 4 (2 items) : 3, 4
5 - 6 (2 items) : 5, 6
7 - 10 (4 items) : 7, 8, 9, 10

C# Iterating an If statement with new value each time

Is it possible to iterate nested if statements with a new value with every single iteration? I am trying to build a 1-dimensional cellular automata (for homework, I cannot deny it) and I'm completely new to C# as the following code will no doubt assure. I have tried to create this program using the most straightforward, basic, DIY methods available and have run myself into a rut.
I've got a string of 1's and 0's of length 8, say
string y;
y = "11110000";
I want to break this set up in 8 substring sets of 3 with each set comprising of a value in y together with a single value on either side of it. So counting from 0, the 3rd set would be 110, the 7th would be 001. However substrings will only provide the 1st to 6th set as I can't loop them around y to my liking so I defined the following-
y1=y.Substring(7,1)+y+y.Substring(0,1);
Using y1 I was able to get out all the substrings necessary. These were defined pretty basically as follows-
string a0, a1, a2, a3, a4, a5, a6, a7;
a0 = y1.Substring(0, 3);
a1 = y1.Substring(1, 3);
a2 = y1.Substring(2, 3);
a3 = y1.Substring(3, 3);
a4 = y1.Substring(4, 3);
a5 = y1.Substring(5, 3);
a6 = y1.Substring(6, 3);
a7 = y1.Substring(7, 3);
The rules for the next generation of cellular automata are up to the user in this program- that is to say the user can choose whether or not a substring, say 111->0 or 1 for all iterations. I used (an awful lot of) if tables in the following way for each substring
{
if (a0=="000")
{
Console.Write(a);
}
else if (a0=="001")
{
Console.Write(b);
}
else if (a0 =="010")
{
Console.Write(c);
}
else if (a0 == "011")
{
Console.Write(d);
}
else if (a0 == "100")
{
Console.Write(e);
}
else if (a0 == "101")
{
Console.Write(f);
}
else if (a0 == "110")
{
Console.Write(g);
}
else if (a0 == "111")
{
Console.Write(h);
}
}
where a,b,c,d,e,f,g,h are ints and are rules chosen by the user. So say for instance the user decides that each set 000 should result in a 1 value, then a=1. b corresponds to {0,0,1}, c to {0,1,0} and so on. However the fairly obvious problem with this method is that I end up with only 1 generation in ints that I can't get at. I'd love to replace y1 with this new generation (converted into a string). If this isn't possible let me know!
This link might also clear things up a bit
and here's how you COULD have gotten an A+ :D
private static int[,] HipPriestsHomework()
{
string y = "11110000";
Console.WriteLine(y);
var rules = new[]
{
new {pattern = 0, result = 0},
new {pattern = 1, result = 1},
new {pattern = 2, result = 1},
new {pattern = 3, result = 1},
new {pattern = 4, result = 1},
new {pattern = 5, result = 0},
new {pattern = 6, result = 0},
new {pattern = 7, result = 0},
};
Dictionary<int, int> rulesLookup = new Dictionary<int, int>();
foreach(var rule in rules)
{
rulesLookup.Add(rule.pattern, rule.result);
}
int numGenerations = 10;
int inputSize = y.Length;
int[,] output = new int[numGenerations, inputSize];
int[] items = new int[y.Length];
for(int inputIndex = 0; inputIndex< y.Length; inputIndex++)
{
string token = y.Substring(inputIndex, 1);
int item = Convert.ToInt32(token);
items[inputIndex] = item;
}
int[] working = new int[items.Length];
items.CopyTo(working, 0);
for (int generation = 0; generation < numGenerations; generation++)
{
for (uint y_scan = 0; y_scan < items.Length; y_scan++)
{
int a = items[(y_scan - 1) % items.Length];
int b = items[y_scan % items.Length];
int c = items[(y_scan + 1) % items.Length];
int pattern = a << 2 | b << 1 | c;
var match = rules[pattern];
output[generation, y_scan] = match.result;
working[y_scan] = match.result;
Console.Write(match.result);
}
working.CopyTo(items, 0);
Console.WriteLine();
}
return output;
}

how to do basic math calculations with a list of numbers and operators

I have a list of type decimal containing 5 numbers: {10, 9, 100,73,3457}. I have another list of 4 operators of type string between these numbers: * multiplication - subtraction / division + adding.
How can I get the result of the string? I do not know how to impose operator precedence.
10 * 9 - 100 / 73 + 3457 = ???
Here is the code I have, I'm approaching the problem in entirely the wrong way, how should it be done?
static List<decimal> numbers = new List<decimal>();
static List<string> operators = new List<string>();
foreach (decimal number in numbers)
{
foreach (string operatorz in operators)
{
resultnumber =
}
}
Hope I've got what you want, This will make a cross-join of all numbers into them-self and then into operators. You've listed binary operators, so I suppose you need two operands for each operator. Number of resulting rows would be = numbers.Length * numbers.Length * operators.Length
void Main()
{
var numbers = new[] { 10, 9, 100, 73, 3457 };
var operators = new [] { "*", "+", "/", "-" };
var r = from n1 in numbers
from n2 in numbers
from op in operators
select string.Format("{0} {1} {2} = {3}",
n1, op, n2, Perform(n1, op, n2));
}
public int Perform(int val1, string #operator, int val2)
{
//main core if your question, consider to extract operators to outer level
var operators = new Dictionary<string, Func<int, int, int>>
{
{"+", (v1, v2) => v1 + v2},
{"/", (v1, v2) => v1 / v2},
{"*", (v1, v2) => v1 * v2},
{"-", (v1, v2) => v1 - v2},
};
return operators[#operator](val1, val2);
}
result would be
10 * 10 = 100
10 + 10 = 20
10 / 10 = 1
10 - 10 = 0
10 * 9 = 90
....
Not entirely clear what you wanted. But assumed those operators in-between the numbers, and resolving to the native operator precedence: Simple way for that is to script it up. Your operator precedence will be native.
Scripting
private static void Main(string[] args)
{
var numbers = new[]{ 10, 9, 100, 73, 3457 };
var ops = new[] { "*","-","/","+" };
if (numbers.Length != ops.Length + 1)
throw new Exception("TODO");
string statement = numbers[0].ToString();
for (int i = 0; i < ops.Length; i++)
{
statement += string.Format(" {0} {1}", ops[i], numbers[i + 1]);
}
Console.WriteLine("Statement: " + statement);
var method = String.Format(#"int Product() {{ return {0}; }} ", statement);
Console.WriteLine("Method: " + method);
var Product = CSScript.Evaluator.CreateDelegate(method);
int result = (int)Product();
Console.WriteLine(result);
}
Result:
Statement: 10 * 9 - 100 / 73 + 3457
Method: int Product() { return 10 * 9 - 100 / 73 + 3457; }
3546
Press any key to continue . . .
http://msdn.microsoft.com/fr-fr/library/s53ehcz3(v=VS.80).aspx
you can use your own class for processing calculations

LINQ to find the closest number that is greater / less than an input

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();

Categories

Resources