List<int> separated into thirds - c#

Assuming I have a list of numbers, which could be any amount, realistically over 15.
I want to separate that list of numbers into three groups depending on their size, small, medium, and large for instance.
What is the best way of achieving this?
I've written out the below, is it necessary to make my own function as per below, or is there anything existing that I can utilise in .NET?
public static List<int> OrderByThree (List<int> list)
{
list.Sort();
int n = list.Count();
int small = n / 3;
int medium = (2 * n) / 3;
int large = n;
// depending if the number is lower/higher than s/m/l,
// chuck into group via series of if statements
return list;
}
Example
Say I have a list of numbers, 1-15 for instance, I want 1-5 in small, 6-10 in medium and 11-15 in large. However I won't know the amount of numbers at the start, no dramas, using list.count I was hoping to divide for my own function.

Since you have the list sorted already, you can use some LINQ to get the results. I'm assuming a right-closed interval here.
list.Sort();
int n = list.Count();
var smallGroup = list.TakeWhile(x => (x <= n / 3)).ToList();
var middleGroup = list.Skip(smallGroup.Count).TakeWhile(x => (x <= (2 * n) / 3)).ToList();
var largeGroup = list.Skip(smallGroup.Count + middleGroup.Count).ToList();
EDIT
As Steve Padmore commented, you probably will want to return a list of lists (List<List<int>>) from your method, rather than just List<int>.
return new List<List<int>> { smallGroup, middleGroup, largeGroup };

This would be a simple way of doing it:
var result = list.GroupBy (x =>
{
if(x <= small) return 1;
if(x <= medium) return 2;
return 3;
});
Or:
var result = list.GroupBy (x => x <= small ? 1 : x <= medium ? 2 : 3);
(This does not require the list to be sorted)

Related

Getting a List<int> from an integer which modulo result is equal to 0 without using loop [duplicate]

All numbers that divide evenly into x.
I put in 4 it returns: 4, 2, 1
edit: I know it sounds homeworky. I'm writing a little app to populate some product tables with semi random test data. Two of the properties are ItemMaximum and Item Multiplier. I need to make sure that the multiplier does not create an illogical situation where buying 1 more item would put the order over the maximum allowed. Thus the factors will give a list of valid values for my test data.
edit++:
This is what I went with after all the help from everyone. Thanks again!
edit#: I wrote 3 different versions to see which I liked better and tested them against factoring small numbers and very large numbers. I'll paste the results.
static IEnumerable<int> GetFactors2(int n)
{
return from a in Enumerable.Range(1, n)
where n % a == 0
select a;
}
private IEnumerable<int> GetFactors3(int x)
{
for (int factor = 1; factor * factor <= x; factor++)
{
if (x % factor == 0)
{
yield return factor;
if (factor * factor != x)
yield return x / factor;
}
}
}
private IEnumerable<int> GetFactors1(int x)
{
int max = (int)Math.Ceiling(Math.Sqrt(x));
for (int factor = 1; factor < max; factor++)
{
if(x % factor == 0)
{
yield return factor;
if(factor != max)
yield return x / factor;
}
}
}
In ticks.
When factoring the number 20, 5 times each:
GetFactors1-5,445,881
GetFactors2-4,308,234
GetFactors3-2,913,659
When factoring the number 20000, 5 times each:
GetFactors1-5,644,457
GetFactors2-12,117,938
GetFactors3-3,108,182
pseudocode:
Loop from 1 to the square root of the number, call the index "i".
if number mod i is 0, add i and number / i to the list of factors.
realocode:
public List<int> Factor(int number)
{
var factors = new List<int>();
int max = (int)Math.Sqrt(number); // Round down
for (int factor = 1; factor <= max; ++factor) // Test from 1 to the square root, or the int below it, inclusive.
{
if (number % factor == 0)
{
factors.Add(factor);
if (factor != number/factor) // Don't add the square root twice! Thanks Jon
factors.Add(number/factor);
}
}
return factors;
}
As Jon Skeet mentioned, you could implement this as an IEnumerable<int> as well - use yield instead of adding to a list. The advantage with List<int> is that it could be sorted before return if required. Then again, you could get a sorted enumerator with a hybrid approach, yielding the first factor and storing the second one in each iteration of the loop, then yielding each value that was stored in reverse order.
You will also want to do something to handle the case where a negative number passed into the function.
The % (remainder) operator is the one to use here. If x % y == 0 then x is divisible by y. (Assuming 0 < y <= x)
I'd personally implement this as a method returning an IEnumerable<int> using an iterator block.
Very late but the accepted answer (a while back) didn't not give the correct results.
Thanks to Merlyn, I got now got the reason for the square as a 'max' below the corrected sample. althought the answer from Echostorm seems more complete.
public static IEnumerable<uint> GetFactors(uint x)
{
for (uint i = 1; i * i <= x; i++)
{
if (x % i == 0)
{
yield return i;
if (i != x / i)
yield return x / i;
}
}
}
As extension methods:
public static bool Divides(this int potentialFactor, int i)
{
return i % potentialFactor == 0;
}
public static IEnumerable<int> Factors(this int i)
{
return from potentialFactor in Enumerable.Range(1, i)
where potentialFactor.Divides(i)
select potentialFactor;
}
Here's an example of usage:
foreach (int i in 4.Factors())
{
Console.WriteLine(i);
}
Note that I have optimized for clarity, not for performance. For large values of i this algorithm can take a long time.
Another LINQ style and tying to keep the O(sqrt(n)) complexity
static IEnumerable<int> GetFactors(int n)
{
Debug.Assert(n >= 1);
var pairList = from i in Enumerable.Range(1, (int)(Math.Round(Math.Sqrt(n) + 1)))
where n % i == 0
select new { A = i, B = n / i };
foreach(var pair in pairList)
{
yield return pair.A;
yield return pair.B;
}
}
Here it is again, only counting to the square root, as others mentioned. I suppose that people are attracted to that idea if you're hoping to improve performance. I'd rather write elegant code first, and optimize for performance later, after testing my software.
Still, for reference, here it is:
public static bool Divides(this int potentialFactor, int i)
{
return i % potentialFactor == 0;
}
public static IEnumerable<int> Factors(this int i)
{
foreach (int result in from potentialFactor in Enumerable.Range(1, (int)Math.Sqrt(i))
where potentialFactor.Divides(i)
select potentialFactor)
{
yield return result;
if (i / result != result)
{
yield return i / result;
}
}
}
Not only is the result considerably less readable, but the factors come out of order this way, too.
I did it the lazy way. I don't know much, but I've been told that simplicity can sometimes imply elegance. This is one possible way to do it:
public static IEnumerable<int> GetDivisors(int number)
{
var searched = Enumerable.Range(1, number)
.Where((x) => number % x == 0)
.Select(x => number / x);
foreach (var s in searched)
yield return s;
}
EDIT: As Kraang Prime pointed out, this function cannot exceed the limit of an integer and is (admittedly) not the most efficient way to handle this problem.
Wouldn't it also make sense to start at 2 and head towards an upper limit value that's continuously being recalculated based on the number you've just checked? See N/i (where N is the Number you're trying to find the factor of and i is the current number to check...) Ideally, instead of mod, you would use a divide function that returns N/i as well as any remainder it might have. That way you're performing one divide operation to recreate your upper bound as well as the remainder you'll check for even division.
Math.DivRem
http://msdn.microsoft.com/en-us/library/wwc1t3y1.aspx
If you use doubles, the following works: use a for loop iterating from 1 up to the number you want to factor. In each iteration, divide the number to be factored by i. If (number / i) % 1 == 0, then i is a factor, as is the quotient of number / i. Put one or both of these in a list, and you have all of the factors.
And one more solution. Not sure if it has any advantages other than being readable..:
List<int> GetFactors(int n)
{
var f = new List<int>() { 1 }; // adding trivial factor, optional
int m = n;
int i = 2;
while (m > 1)
{
if (m % i == 0)
{
f.Add(i);
m /= i;
}
else i++;
}
// f.Add(n); // adding trivial factor, optional
return f;
}
I came here just looking for a solution to this problem for myself. After examining the previous replies I figured it would be fair to toss out an answer of my own even if I might be a bit late to the party.
The maximum number of factors of a number will be no more than one half of that number.There is no need to deal with floating point values or transcendent operations like a square root. Additionally finding one factor of a number automatically finds another. Just find one and you can return both by just dividing the original number by the found one.
I doubt I'll need to use checks for my own implementation but I'm including them just for completeness (at least partially).
public static IEnumerable<int>Factors(int Num)
{
int ToFactor = Num;
if(ToFactor == 0)
{ // Zero has only itself and one as factors but this can't be discovered through division
// obviously.
yield return 0;
return 1;
}
if(ToFactor < 0)
{// Negative numbers are simply being treated here as just adding -1 to the list of possible
// factors. In practice it can be argued that the factors of a number can be both positive
// and negative, i.e. 4 factors into the following pairings of factors:
// (-4, -1), (-2, -2), (1, 4), (2, 2) but normally when you factor numbers you are only
// asking for the positive factors. By adding a -1 to the list it allows flagging the
// series as originating with a negative value and the implementer can use that
// information as needed.
ToFactor = -ToFactor;
yield return -1;
}
int FactorLimit = ToFactor / 2; // A good compiler may do this optimization already.
// It's here just in case;
for(int PossibleFactor = 1; PossibleFactor <= FactorLimit; PossibleFactor++)
{
if(ToFactor % PossibleFactor == 0)
{
yield return PossibleFactor;
yield return ToFactor / PossibleFactor;
}
}
}
Program to get prime factors of whole numbers in javascript code.
function getFactors(num1){
var factors = [];
var divider = 2;
while(num1 != 1){
if(num1 % divider == 0){
num1 = num1 / divider;
factors.push(divider);
}
else{
divider++;
}
}
console.log(factors);
return factors;
}
getFactors(20);
In fact we don't have to check for factors not to be square root in each iteration from the accepted answer proposed by chris fixed by Jon, which could slow down the method when the integer is large by adding an unnecessary Boolean check and a division. Just keep the max as double (don't cast it to an int) and change to loop to be exclusive not inclusive.
private static List<int> Factor(int number)
{
var factors = new List<int>();
var max = Math.Sqrt(number); // (store in double not an int) - Round down
if (max % 1 == 0)
factors.Add((int)max);
for (int factor = 1; factor < max; ++factor) // (Exclusice) - Test from 1 to the square root, or the int below it, inclusive.
{
if (number % factor == 0)
{
factors.Add(factor);
//if (factor != number / factor) // (Don't need check anymore) - Don't add the square root twice! Thanks Jon
factors.Add(number / factor);
}
}
return factors;
}
Usage
Factor(16)
// 4 1 16 2 8
Factor(20)
//1 20 2 10 4 5
And this is the extension version of the method for int type:
public static class IntExtensions
{
public static IEnumerable<int> Factors(this int value)
{
// Return 2 obvious factors
yield return 1;
yield return value;
// Return square root if number is prefect square
var max = Math.Sqrt(value);
if (max % 1 == 0)
yield return (int)max;
// Return rest of the factors
for (int i = 2; i < max; i++)
{
if (value % i == 0)
{
yield return i;
yield return value / i;
}
}
}
}
Usage
16.Factors()
// 4 1 16 2 8
20.Factors()
//1 20 2 10 4 5
Linq solution:
IEnumerable<int> GetFactors(int n)
{
Debug.Assert(n >= 1);
return from i in Enumerable.Range(1, n)
where n % i == 0
select i;
}

Is there a known fast algorithm for finding all pairs of numbers that multiply to a given number?

For example, the pairs that multiple to 16 are {(16,1), (2,8), (4,4)} and the pairs that multiply to 15 are {(15,1), (5,3)} but I'm not of how to construct an algorithm better than brute force. My method looks like
private static IEnumerable<Tuple<int, int>> Multipliers(int m)
{
var found = new HashSet<int>();
foreach(int v in Enumerable.Range(1, m))
{
int d = m / v;
bool even = m % v == 0;
if(even && found.Contains(d))
{
yield return Tuple.Create(d, v);
}
found.Add(v);
}
}
which is sloppy and probably not as efficient as possible.
Here's a sample method for you, though I'm not sure if it's the "most efficient one", per se:
public static IEnumerable<(int A, int B)> Multipliers(int m)
{
yield return (m, 1);
int i = 2;
int lastVal = m / 2;
while (i <= lastVal)
{
if (m % i == 0)
{
lastVal = m / i;
yield return (lastVal, i);
}
i++;
}
}
public static void Main(string[] args)
{
foreach (var pair in Multipliers(16))
{
Console.WriteLine("{0}, {1}", pair.A, pair.B);
}
}
Using C#7 tuple return syntax because I can. :P
EDIT: Switched from a for loop to a while loop to handle the case for when m <= 2.
EDIT 2: As suggested by Adwaenyth, this is a midified version of the method that checks if m is even. If not, then skip all even potential factors. Also, as suggested by other answers, limit the iteration to the square root of m instead of m/2:
public static IEnumerable<(int A, int B)> Multipliers(int m)
{
yield return (m, 1);
int lastVal = (int)Math.Sqrt(m);
int increment = (m % 2 != 0) ? 2 : 1;
int i = (m % 2 != 0) ? 3 : 2;
while (i <= lastVal)
{
if (m % i == 0)
{
lastVal = m / i;
yield return (lastVal, i);
}
i += increment;
}
}
I'm pretty sure that this is as efficient as this particular approach can go. To make it better, you would tweak it to check against all prime numbers and their multiples up to the square root of m. Ideally, you would do this against a look-up table, since a lot of the time you save by only comparing prime numbers would be lost while generating them. (For really large ms, it still comes out faster, though.)
EDIT 3 I discovered that my previous code's use of lastVal was making the required time be a bit inconsistent as well as introducing a weird bug that made it sometimes forget to check larger factors. Here's an update that should fix those problems:
public static IEnumerable<(int A, int B)> Multipliers(int m)
{
yield return (m, 1);
int finalVal = (int)Math.Sqrt(m);
int increment = m % 2 != 0 ? 2 : 1;
int i = m % 2 != 0 ? 3 : 2;
while (i <= finalVal)
{
if (m % i == 0)
{
yield return (m / i, i);
}
i += increment;
}
}
First generate a list of primes up to the square root of input N you will have, for each prime p check if it divides N. If it does then N = N/p and repeat this recursively until all primes in list has have been exhausted or N/p = 1.
In the rare case of where no primes in list can divide the input, then your number is a prime. The only pairs are {(1, N), (N, 1)}. This should get more rare as your input increases exponentially.
For the other case count all the prime divisors and the times they occur. Finally find all combination of products of the primes up to square root of N, which will all be part of pairs that divide N.
I think that the best way to do this is perform prime factorization algorithm. But you should note that it is very difficult area of mathematics. You can find articles in http://mathworld.wolfram.com/PrimeFactorizationAlgorithms.html
From sequence of prime numbers you can combine all possible pairs which form given number

Find a value between a List's upper and lower limits

I'm currently calculating tax rate by the following way
int testValue = 180000;
List<TaxBracket> taxes = new List<TaxBracket>();
taxes.Add(new TaxBracket(18199, 0)); //0 to 18199
taxes.Add(new TaxBracket(36999, 19)); //18200 to 36999
taxes.Add(new TaxBracket(79999, Convert.ToDecimal(32.50D))); //37000 to 79999
taxes.Add(new TaxBracket(179999, 37)); //80000 to 179999
taxes.Add(new TaxBracket(180000, 47)); //180000
decimal result = taxes[taxes.Count-1].Value;
for (int i = 0; i < taxes.Count; i++)
{
if (i == 0)
{
if (testValue < taxes[i].Limit)
result = 0;
}
if (i > 0)
{
if (testValue < taxes[i].Limit && testValue > taxes[i - 1].Limit)
{
result = taxes[i].Value;
}
}
}
Console.WriteLine(result);
Is there any alternate in LINQ to do this instead of using this old-school approach? Looks pretty close to this but a bit different.
If I understood correctly this is what you want:
var result = taxes.OrderBy(item => item.Limit)
.SkipWhile(item => item.Limit < testValue)
.FirstOrDefault()?.Value;
It will order your collection from smallest Limit to largest and then will Skip until it reaches a Limit that is equal or greater than your testValue. Because collection is ordered then the FirstOrDefault and it's value.
Or:
var result = taxes.Where(item => item.Limit >= testValue )
.OrderBy(item => item.Limit)
.FirstOrDefault()?.Value;
This way looks at the problem from a different direction. Take only the items that are equal or to testValue and then order them ant take the first.
As a Linq alternative I suggest using binary search, providing that taxes is sorted:
int index = taxes.BinarySearch(
new TaxBracket(testValue, -1), // -1: this parameter is ignored
Comparer<TaxBracket>.Create((left, right) => left.Limit.CompareTo(right.Limit)));
if (index < 0)
index = ~index - 1; // in between of two indexes
var result = taxes[index].Value;
Binary search can be useful when you work with long list (the algorithm ensures O(log(N)) complexity, when Linq provides O(N) one); but when taxes is small, Linq SkipWhile (see Gilad Green's answer) is more readable

Create a list of sequential numbers excluding one number

Requirements:
Create a list of n sequential numbers starting at a.
Exclude number x.
This is the best I have right now, the problem being that it creates n + 1 numbers if x is not within the range.
var numbers = Enumerable
.Range(a, numberOfDataRowsToAdd + 1)
.Where(i => i != TechnicalHeaderRowIndex);
Example 1 should produce 0,1,2,3,4,5,6,7,8,9.
var a = 0;
var n = 10;
var x = 11;
Example 2 should produce 0,1,2,3,4,5,7,8,9,10.
var a = 0;
var n = 10;
var x = 6;
Here is a Fiddle that demonstrates Mark's answer.
How about
Enumerable.Range(a, n + 1)
.Where(i => i != x)
.Take(n);
My example, how it can be done without LINQ and extra loop iterations:
public static IEnumerable<int> GenerateNumbers(int a, int n, int x)
{
for (var i = 0; i < n; i++)
{
if (a == x)
{
i--;
a++;
continue;
}
yield return a++;
}
}
But if you don't want create new method for this purpose, Mark Sowul or Jakub Lortz answers are better.
The problem can be described as
Get n + 1 sequential numbers starting from a
If x is in the range, remove x, otherwise remove the maximum number from the list
Translated to C#
int numberToExclude = Math.Min(n + a, x);
var numbers = Enumerable.Range(a, n + 1).Where(i => i != numberToExclude);
It makes sense to generate only necessary values instead of generating n + 1 values and then remove x:
Enumerable.Range(a, n).Select(i => i < x ? i : i + 1);
Example 1: 0,1,2,3,4,5,6,7,8,9.
Example 2: 0,1,2,3,4,5,7,8,9,10.
You can drop the last if your enumerable count is bigger than numberOfDataRowsToAdd
Extension method:
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> enumerable)
{
return enumerable.Take(enumerable.Count()-1);
}
Usage:
var numbers = Enumerable
.Range(a, numberOfDataRowsToAdd + 1)
.Where(i => i != TechnicalHeaderRowIndex);
if(numbers.Count() > numberOfDataRowsToAdd)
numbers = numbers.DropLast();
I don't see what really is the challenge - Linq shortest or fastest or just working. How about the natural (which should also be the fastest Linq based)
var numbers = a <= x && x < a + n ?
Enumerable.Range(a, x - a).Concat(Enumerable.Range(x + 1, a - x + n)) :
Enumarble.Range(a, n);

Find numbers in List<int> with specified difference

For a given a space separated list of numbers, what is the most effecient way of counting the total pairs of numbers which have a difference of N.
e.g. command line in put would be:
5 2
where 5 is the count of numbers to follow and 2 is the difference required
1 5 3 4 2
the 5 numbers to be considered
Output should be
3
because (5,3), (4,2) and (3,1) all have a diff of 2
I can get this algorithm to work, but is there a more efficient way of doing this if you have large sets of numbers to work with? I have incluced three comparison options and the second one should be better than the third but is there something I'm forgetting which could make it much quicker?
private static void Difference()
{
string[] firstInput = SplitInput(Console.ReadLine());
int numberOfNumbers = int.Parse(firstInput[0]);
int diffOfNumbers = int.Parse(firstInput[1]);
string[] secondInput = SplitInput(Console.ReadLine());
List<int> numbers = secondInput.Select(x => Int32.Parse(x)).ToList();
int possibleCombinations = 0;
// Option 1
foreach (int firstNumber in numbers)
{
List<int> compareTo = numbers.GetRange(numbers.IndexOf(firstNumber) + 1, numbers.Count - numbers.IndexOf(firstNumber) - 1);
foreach (int secondNumber in compareTo)
{
int diff = firstNumber - secondNumber;
if (Math.Abs(diff) == diffOfNumbers)
{
possibleCombinations++;
}
}
}
// Option 2
foreach (int firstNumber in numbers)
{
if (numbers.Contains(firstNumber + diffOfNumbers))
{
possibleCombinations++;
}
}
// Option 3
foreach (int firstNumber in numbers)
{
foreach (int secondNumber in numbers)
{
int diff = firstNumber - secondNumber;
if(Math.Abs(diff) == diffOfNumbers)
{
possibleOptions++;
}
}
}
Console.WriteLine(string.Format("Possible number of options are: {0}", possibleCombinations));
Console.ReadLine();
}
private static string[] SplitInput(string input)
{
return input.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
}
If duplicate numbers are not allowed or to be ignored (only count unique pairs), you could use a HashSet<int>:
HashSet<int> myHashSet = ...
int difference = ...
int count;
foreach (int number in myHashSet)
{
int counterpart = number - difference;
if (myHashSet.Contains(counterpart))
{
count++;
}
}
Given the constraints of the problem, where N is the "count of numbers to follow" [1..N], and M is the difference (N=5 and M=2 in the example), why not just return N - M ?
This is done easily with LINQ, allowing for duplicates:
var dict = numbers.GroupBy(n => n).ToDictionary(g => g.Key, g => g.Count());
return dict.Keys.Where(n => dict.ContainsKey(difference-n)).Select(n => dict[difference - n]).Sum();
In the first line we create a dictionary where the keys are the distinct numbers in the input list (numbers) and the values are how many times they appear.
In the second, for each distinct number in the list (equivalent to the keys of the dictioanry) we look to see if the dictionary contains a key for the target number. If so, we add the number of times that target number appeared, which we previously stored as the value for that key. If not we add 0. Finally we sum it all up.
Note in theory this could cause arithmetic overflows if there's no bound other than Int.MinValue and Int.MaxValue on the items in the list. To get around this we need to do a "safe" check, which first makes sure that the difference won't be out of bounds before we try to calculate it. That might look like:
int SafeGetCount(int difference, int number, Dictionary<int,int> dict)
{
if(difference < 0 && number < 0 && int.MinValue - difference > number)
return 0;
if(difference > 0 && number > 0 && int.MaxValue - difference < number)
return 0;
return dict.ContainsKey(difference-number) ? dict[difference - number] : 0;
}
Update
There are a couple of things note entirely clear from your question, like whether you actually want to count duplicate pairs multiple times, and does swapping the numbers count as two different pairs. e.g. if (1,4) is a pair, is (4,1)? My answer above assumes that the answer to both of those questions is yes.
If you don't want to count duplicate pairs multiple times, then go with the HashSet solution from other answers. If you do want to count duplicate pairs but don't want to count twice by swapping the values in the pair, you have to get slightly more complex. E.g.:
var dict = numbers.GroupBy(n => n).ToDictionary(g => g.Key, g => g.Count());
var sum = dict.Keys.Where(n => n*2 != difference)
.Where(n => dict.ContainsKey(difference-n))
.Select(n => dict[difference - n]).Sum()/2;
if(n%2 == 0)
{
sum += dict.ContainsKey(n/2) ? dict[n/2] : 0
}
return sum;
how about sorting the list then iterating over it.
int PairsWithMatchingDifferenceCount(
IEnumerable<int> source,
int difference)
{
var ordered = source.OrderBy(i => i).ToList();
var count = ordered.Count;
var result = 0;
for (var i = 0; i < count - 1; i++)
{
for (var j = i + 1; j < count; j++)
{
var d = Math.Abs(ordered[j] - ordered[i]);
if (d == difference)
{
result++;
}
else if (d > difference)
{
break;
}
}
}
return result;
}
so, as per the example you would call it like this,
PairsWithMatchingDifferenceCount(Enumerable.Range(1, 5), 2);
but, if the sequence generation is a simple as the question suggests why not just.
var m = 5;
var n = 2;
var result = Enumerable.Range(n + 1, m - n)
.Select(x => Tuple.Create(x, x - n)).Count();
or indeed,
var result = m - n;

Categories