Formula to produce 1 for positive integers and 0 otherwise - c#

I have a function (f) the takes a number of items (n) and a number of columns (c) and returns the optimal layout as an array of items per column. I define optimal as being as square as possible. So f(4,4) would return [4,4,4,4], f(17,4) would return [5,4,4,4], and f(1,4) would return [1,0,0,0]. My function works correctly in all my tests, but I am looking to alter it. My desire to do this is not because I am looking increase performance. I just want to do this, because I am experimenting and want to learn different techniques.
Here is the code:
public static int[] f(int n, int c){
int[] a = new int[c];
if(c>0 && n>=0){
int opt = (n-(n%c))/c;
n = n - (opt*c);
for(int i = 0;i<a.Length;i++){
a[i] = opt;
if(n>0){
a[i]++;
n--;
}
}
}
return a;
}
The function works by first determining the optimal number of items per col:
int opt = (n-(n%c))/c;
So f(17,4) would yield 4, f(19,4) would also yield 4, and f(3,4) would yield 0. Then the reminder is calculated:
n = n - (opt*c);
I then loop through the array (of length c) and assign a[i] equal to the optimal value. Finally, if the reminder is greater than 0 I add 1 to a[i]. This equally distributes the reminder across the array. This is the part I would like to alter.
Instead of checking if(n>0) and adding 1 to the array is there a formula I could use that might look like:
a[i] = opt + n*?????;
So n*??? would always equal 1 if n is greater than 0 and 0 if n is 0 or less?

The simple answer to your question is to use an expression with the conditional operator:
a[i] = opt + (n > 0 ? 1 : 0);
(n > 0 ? 1 : 0) will be 1 if n is greater than 0, and 0 otherwise.
On that note, there is a clearer and more concise way to implement your algorithm.
Determine the total number of items that can be distributed evenly between the slots (call this average). This has the value n / c (using integer division).
Determine the remainder that would be left after those are evenly distributed (call this remainder). This has the value n % c.
Put the value average + 1 in the first remainder slots, and put average in the rest.
The implementation for this would be:
public static int[] Distribute(int total, int buckets)
{
if (total < 0) { throw new ArgumentException("cannot be less than 0", "total"); }
if (buckets < 1) { throw new ArgumentException("cannot be less than 1", "buckets"); }
var average = total / buckets;
var remainder = total % buckets;
var array = new int[buckets];
for (var i = 0; i < buckets; i++)
{
array[i] = average + (i < remainder ? 1 : 0);
}
return array;
}
And the obligatory Linq version:
public static int[] DistributeLinq(int total, int buckets)
{
if (total < 0) { throw new ArgumentException("cannot be less than 0", "total"); }
if (buckets < 1) { throw new ArgumentException("cannot be less than 1", "buckets"); }
var average = total / buckets;
var remainder = total % buckets;
return Enumerable.Range(1, buckets)
.Select(v => average + (v <= remainder ? 1 : 0))
.ToArray();
}

If you want to use a formula:
Math.Max(n - Math.Abs(n - 1), 0)
should do the trick.
Your code should look like:
a[i] = opt + Math.Max(n - Math.Abs(n - 1), 0)

Another option for a formula would be
Math.Max(Math.Sign(n), 0)
If you are looking for a mathematical formula, I'm not sure you're going to find it as the function is discontinuous at n = 0.

How about a simple function which outputs int on a bool expression?
int IsPositive(int number)
{
//if number is > 0 return integer one (1), else return integer zero (0)
return number > 0 ? 1 : 0;
}
You can then use this in your code as such:
a[i] = opt + IsPositive(n);
//opt + 1 if n > 0, opt + 0 if n <= 0
Update: per your comment, you can just move the evaluation inline:
a[i] = opt + (n > 0 ? 1 : 0);
As an aside: you should make #BradleyDotNET's comment one of your programming mottos.

Related

c# find if whether the number is happy or not

Im trying to understund how do I find whether the number is Happy Number or not,
I know that i need to check if the unit digit and the digit in the highest number location are greater
then the numbers in the middele.
`example:
given number: 63240
the unit: 6
the number in the highest location:0
are both of them greater then 3 and 2 and4(middle) ? yes
result: true (for that case)
the quation is:
write a program that get a number from user, the program will print if the given number from the user is a happy number or not
I know how to find the units and the highest number location, but got stack figure it out how to
how to use the digits in the middle in order to find the answer for that..
notice that the only class we've learned so fat is Math,(not even string yes)
we also learned while and for but nothing so far..
I also know that in order to go through all digit in given number i need to use the while loop,
but I dont know how do I use it in order to use them to get to the answer..
my code so far:
int number;
int units;
int highestDigitLoc;
bool isHappyNumber = true;
int count = 0;
Console.WriteLine("enter a number:");
number = int.Parse(Console.ReadLine());
while(number > 0)
{
count++;
units = number % 10;
highestDigitLoc = number / 10;
}
thanks
This link explains what Happy Number's are in a simple way. Basically you have to keep suming the square of each digit present in the number, until the result equals 1. This proccess can go on indefinitely, but fortunately we know for certain that if the sum equals 4, it will never result in a Happy Number. Therefore, we can do the following:
private static bool IsHappy(int n)
{
if (n == 1)
return true;
else if (n == 0 || n == 4)
return false;
else
return IsHappy(SumDigitSquares(n));
}
private static int SumDigitSquares(int n)
{
if (n < 10)
return n * n;
else
return SumDigitSquares(n % 10) + SumDigitSquares(n / 10);
}
Usage:
bool result = IsHappy(63240); //false
Well, your question very vague, however, we can turn the number into an array of digits int[] digits
using System.Linq;
...
int[] digits = null;
while (true) {
Console.WriteLine("enter a number:");
// string : let's solve for arbitrary long numbers (no necessary int)
string number = Console.ReadLine().Trim();
if (string.IsNullOrEmpty(number))
Console.WriteLine("Empty string is not enough");
else if (number.All(c => c >= '0' && c <= '9')) {
// This code preserves leading zeroes
digits = number.Select(c => c - '0').ToArray();
// This code removes leading zeroes
//digits = number
// .SkipWhile(c => c == '0')
// .Select(c => c - '0')
// .DefaultIfEmpty()
// .ToArray();
break;
}
else
Console.Write("Not a valid integer value. Please, try again.");
}
Then we can use this int[] digits to implement any logic required.
Please, note, that we preserve leading zeroes:
"63240" -> int[] {6, 3, 4, 2, 0}
"063240" -> int[] {0, 6, 3, 4, 2, 0}
e.g.
let a number be happy if and only if
It contains at least 3 digits (in order to have middle ones)
Max of the first and last digits is greater than max of all the other digits
In our case with 63240
63240 has 5 digits, the condition holds
Max(0, 6) == 6 > Max(3, 2, 4) == 4, the condition holds
Code:
bool isHappyNumber =
digits.Length >= 3 &&
Math.Max(digits[0], digits[digits.Length - 1]) >
digits.Skip(1).Take(digits.Length - 2).Max();
Edit: let's implement isHappyNumber with good old for loops:
int maxFirstAndLast = digits[0] > digits[digits.Length - 1]
? digits[0]
: digits[digits.Length - 1];
int maxMiddle = 0;
for (int i = 1; i < digits.Length - 1; ++i)
if (digits[i] > maxMiddle) then
maxMiddle = digits[i];
bool isHappyNumber =
digits.Length >= 3 &&
maxFirstAndLast > maxMiddle;
//Remeber to add using System.Linq;
public static bool IsHappyNumber(int num)
{
var numbers = new List<int>();
while (true)
{
int sum = 0;
var digits = num.ToString().Select(x => int.Parse(x.ToString())).ToList();
foreach (var digit in digits)
sum += digit * digit;
if (numbers.Contains(sum))
break;
numbers.Add(sum);
num = sum;
}
return numbers.LastOrDefault() == 1;
}

Solving modulo equations programmatically

My goal is to implement a (simple) check digit alglorithm as described Here
My implemantion is the following but I am not sure if it is optimal:
private int CheckDigit(string SevenDecimal)
{
///Get UPC check digit of a 7-digit URI
///Add odd and multiply by 3 =Odds
///Add even =Evens
///Add Odds+Evens=sum
///Check digit is the number that makes Sum divisble by 10
int Odds = 0;
int Evens = 0;
int sum = 0;
int index = 0;
foreach (char digit in SevenDecimal)
{
index++;
int Digit = int.Parse(digit.ToString());
if (index % 2 == 0)
{
Evens +=Digit;
}
else
{
Odds +=Digit;
}
}
Odds = Odds * 3;
sum = Odds + Evens;
for (int i = 0; i < 10; i++) ///Brute force way check for better implementation
{
int Localsum;
Localsum = sum + i;
if (Localsum % 10 == 0)
{
return i;
}
}
return -1;//error;
}
My main concern is in the final for loop which as I describe is totallly brute.
Is there a better way to obtaining the check digit?
More precisely which is the best way to solve programmatically, the equation:
(sum+x)%10=0 //solve for x
To find "how much i you have to add to make the last digit of a number a 0", you can subtract from 10:
int checkDigit = (10 - (sum % 10)) % 10;
The second modulo is used for the special case when sum % 10 == 0, because 10 - 0 = 10
You are asking the wrong question. The expression is not one of equivalence thus x is not a value. The solution is that x is an infinite number of values each of which correctly solve the equation. As such you don't really want to solve for x but just check if x is in this solution space. You can check this simply with:
remainder = base - (sum % base)
You can then test if x sums up to the remainder with:
if (x % base === base - (sum % base))
{
// (sum + x) % base = 0 is true
}
Replace base with 10and you'll have it.

PermCheck codility. O(N) time complexity

Hi i have this solution for PermCheck codility. Here is the link which includes the question: https://codility.com/demo/results/demo73YNCU-8FK/
I got 100% for it but i got a time complexity of O(N * log(N)) or O(N).
How could i make this code O(N)? Could you also give a brief description of what makes code O(N)? Thankyou.
Code here for shortcut:
Array.Sort(A);
if(A[0] == 1 && A.Length == 1) return 1;
if(A[0] != 1) return 0;
int n = 0;
for(int i = 0; i < A.Length; i++)
{
if(i < A.Length - 1)
{
if(A[i+1] == A[i] + 1)
{
n += 1;
}
else
{
return 0;
}
}
}
return 1;
Create a bool array which has the same size as the input, N, and leave all elements as the default false value. Loop through every element X of the input. If X is greater than N then return false. If array[N-1] is true, return false. Otherwise set array[N-1] to true. Repeat. This is O(N).
Explanation: First, if you have a permutation, then you need elements 1..N, but if any element is larger than N, then surely some elements are missing. Second, if an element occurs twice, it's a problem, that's why we create the bool array to remember already seen elements.
My python solution (doesn't need additional libraries, looks pythonic and not difficult to understand by others):
def solution(A): return 1 if len(set(A)) == len(A) == sorted(A)[-1] else 0
It can be simplified to:
def solution(A):
if len(set(A)) == len(A):
if len(A) == sorted(A)[-1]:
return 1
return 0
I checked two moments:
1: Length of set from array (set can't have duplicates) is equals to length of initial array
Arrays passed (no duplicates):
[1, 3, 2, 4], [4, 3, 2, 5]
Arrays failed:
[1, 1, 2, 4], [5, 6, 6, 1]
2: Length of initial array is equals to last element in sorted array
Arrays passed:
[1, 2, 3, 4]: Length is equal to last element => return 1
Arrays failed:
[2, 3, 4, 5]: Length is not equal to last element => return 0
This code doesn't work if A contains 0 or negative elements, but according to task details: each element of array A is an integer within the range [1..1,000,000,000].
Codility shows 100% and O(N) or O(N * log(N))
Tried to make it O(N) (suggested by fejesjoco):
def solution(A):
array_length = len(A)
seen_values = [False] * array_length
for x in A:
if x > array_length:
return 0
else:
if seen_values[x - 1]:
return 0
else:
seen_values[x - 1] = True
return 1
Codility result 100% Detected time complexity: O(N) or O(N * log(N))
Both codes shows equal result and time complexity. Maybe codility can't evaluate it right?
Here is my 100/100 answer:
same Idea as #fejesjoco
https://codility.com/demo/results/demoNR485D-33P/
You can change int to long to get performance.
public int solution(int[] A)
{
// idea: add to set,dictionary. Count the size and compare to N.
// dedupe data when needed.
var set = new HashSet<int>();
var max = int.MinValue;
foreach (var item in A)
{
if (set.Contains(item)) return 0;
set.Add(item);
if (item > max) max = item;
}
return set.Count == max ? 1 : 0;
}
This is my solution that scored 100% in correctness and performance.
def solution(A):
arraylength = len(A)
if (arraylength > 100000):
raise ValueError("Out of bound range")
arr = sorted(A)
for i in range(arraylength):
if (arr[i] != i+1):
return 0
return 1
I know that this questions is asked long time ago but it is still active in codility.
Possible solution:
public int solution(int[] A)
{
return (Enumerable.Range(1, A.Length).Except(A).Count() == 0) ? 1 : 0;
}
Following the suggestion by fejesjoco,
Boolean[] bln = new Boolean[A.Length];
for (int i = 0; i < A.Length; i++)
{
if (A[i] > A.Length) // more than array length
return 0;
if (bln[A[i]-1]) // same value twice
return 0;
bln[A[i]-1] = true;
}
return 1;
This was my solution, it scored 100%. Do not forget to add "using System.Linq".
int distinctLength = A.Distinct().ToArray().Length;
// The array length should equal to the distinct array length which is also the maximum value in array A.
if (A.Length == distinctLength && distinctLength == A.Max()) { return 1; }
return 0;
Swift Solution 100%
public func solution(_ A : inout [Int]) -> Int {
// write your code in Swift 4.2.1 (Linux)
let sorted = A.sorted()
for (index, value) in sorted.enumerated() {
if index+1 != value {
return 0
}
}
return 1
}

Spread number of items equally across hours

I have a variable number of items that I want to spread across a variable amount of hours. The issue I'm having is how to distribute the remainder so that the space between the "overhang" is as equal as possible. For example, if I have 13 items (X) spread across 5 hours I want to end up with
Hours: 1 2 3 4 5
---------------------------------
x x x x x
x x x x x
x x x
I'm not sure if I'm overthinking this. I'm currently checking if the number of items is greater than the number of hours. If that's true, I'm dividing (number of items/number of hours). Then I think that I have to divide (number of hours/remainder)... But for the above example: 5/3=1.6, which rounds to 2. I think that I have to use Math.Floor somehow, but I'm currently not really sure how.
For 4 items across 5 hours, I'd like to end up with the Xs
For 2 items with the Ys
For 1 item with the Zs
1 2 3 4 5
------------------------
x x x x
y y
z
The number of items and the number of hours are variable.
Okay, I think I'm currently on the right track. I'm now trying to split the bins in half and put one of the remainder in the center-bin. This repeats recursively until the remainder is 0.
EDIT: Fixed issue with even hours and items.
This is a hard problem and below is the solution. I've written solution for a completely generic problem so it works for arbitrary hours and number of items. Here's the example outputs:
Items=10, Hours=14
XX XX XX XX XX
Items=11, Hours=14
XX XXXXX XX XX
Items=12, Hours=14
XX XXXXXXXX XX
Items=16, Hours=13
XXXXXXXXXXXXX
XXX
Items=17, Hours=13
XXXXXXXXXXXXX
X X X X
Items=18, Hours=13
XXXXXXXXXXXXX
X XXX X
Items=19, Hours=13
XXXXXXXXXXXXX
X X X X X X
Items=20, Hours=13
XXXXXXXXXXXXX
X X XXX X X
Items=21, Hours=13
XXXXXXXXXXXXX
X XX X X XX X
Here's how below solution works:
Number of filled lines are trivial which you can get it by (items/hours) * hours.
The last line is where all the magic is required.
When number of remaining items are odd we want to turn on the center. If number of hours are also odd then center is well defined but otherwise we are out of luck and we would have some "imbalance" in that case.
For even items we make them in to pairs and distribute each pair in the order of balanced binary tree. This basically means we first put each pair at the end. Then next pair half way through and recursively follow the pattern. This might be the most difficult part to understand so paper and pen is recommended :).
And here's the code:
static void Main(string[] args)
{
var hours = 13;
for (var items = 16; items < 22; items++)
PrintDistribution(items, hours);
}
private static void PrintDistribution(int items, int hours)
{
Console.WriteLine(string.Format("\nItems={0}, Hours={1}", items, hours));
for (var i = 0; i < (items / hours) * hours; i++)
{
Console.Write('X');
if ((i + 1) % hours == 0)
Console.WriteLine();
}
var line = new StringBuilder(new string(' ', hours));
var remaining = items % hours;
var evens = remaining / 2;
var odd = remaining - (evens * 2);
var seq = BinaryTreeSequence(hours / 2).GetEnumerator();
for (var i = 0; i < evens; i++)
{
seq.MoveNext();
line[seq.Current] = 'X';
line[hours - seq.Current - 1] = 'X';
}
if (odd > 0)
if (hours % 2 == 0)
{
seq.MoveNext();
line[seq.Current] = 'X';
}
else
line[hours / 2] = 'X';
Console.WriteLine(line);
}
public static IEnumerable<int> BinaryTreeSequence(int count)
{
if (count > 1)
yield return count - 1;
if (count > 0)
yield return 0;
var seqQueue = new Queue<Tuple<int, int, int>>();
Enqueue(seqQueue, 0, count - 1);
for (var seqIndex = count - 2; seqIndex > 0; seqIndex--)
{
var moreNeeded = seqQueue.Count < seqIndex;
var seq = seqQueue.Dequeue();
yield return seq.Item1;
if (moreNeeded)
{
Enqueue(seqQueue, seq.Item1, seq.Item3);
Enqueue(seqQueue, seq.Item2, seq.Item1);
}
}
}
private static void Enqueue(Queue<Tuple<int, int, int>> q, int min, int max)
{
var midPoint = (min + max) / 2;
if (midPoint != min && midPoint != max)
q.Enqueue(Tuple.Create(midPoint, min, max));
}
Here's an approximate solution. It returns tuples with the zero-based index, and the item. (I assumed the items might be important, and not just dummy values like your xs) It doesn't choose the optimal spacing in some cases, but I think it'll always be close (i.e. gaps no more than 1 larger than necessary), and always return the correct number of items.
public static IEnumerable<Tuple<int, T>> SplitItems<T>(IEnumerable<T> items, int count)
{
var itemList = items.ToList();
int lastRowCount = itemList.Count % count;
int wholeRowItemCount = itemList.Count - lastRowCount;
// return full rows: 0 <= i < wholeRowCount * count
for (int i = 0; i < wholeRowItemCount; i++)
{
yield return Tuple.Create(i % count, itemList[i]);
}
if (lastRowCount > 0)
{
//return final row: wholeRowCount * count <= i < itemList.Count
double offset = (double)count / (lastRowCount + 1);
for (double j = 0; j < lastRowCount; j++)
{
int thisIntPos = (int)Math.Round(j * count / (lastRowCount + 1) + offset, MidpointRounding.AwayFromZero);
yield return Tuple.Create(thisIntPos, itemList[wholeRowItemCount + (int)j]);
}
}
}
As an example of how to use it:
Console.WriteLine(string.Join("\r\n", SplitItems(Enumerable.Range(1, 12), 5)));
// prints
(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(0, 6)
(1, 7)
(2, 8)
(3, 9)
(4, 10)
(2, 11)
(3, 12)
(this is suboptimal because the last line has items at 2-3 and empty spaces/gaps at 0-1 and 4, while your solution with ys only has gaps of size 1)
Also, though it doesn't match your example (which would be 0, 2, 4 in my zero-based indexing), the following example satisfies the algorithm that you've defined so far, since it's minimized the gap size. (1-size gaps at indices 0 and 2, instead of yours, which has the gaps at 1 and 3) If 0, 2, 4 is indeed better than 1, 3, 4, you need to decide why exactly, and add that to your algorithm definition.
Console.WriteLine(string.Join("\r\n", SplitItems(Enumerable.Range(1, 3), 5)));
// prints
(1, 1)
(3, 2)
(4, 3)
Actually, this is a sort of restricted partition problem. For dividing d items across h hours, you want to find a partition of h-d with no more than h-d parts where max(parts) is the smallest it can be. E.g. dividing 2 items among 5 hours: the optimal solution is 1+1+1, because it has no more than 3 parts, and max(parts) == 1, which is the best you can do. As an example without a single solution, 3 items among 5 hours has 1+1, but there are different ways to arrange it, including 0,2,4, 1,3,4, and 0,2,3.

Best way to find all factors of a given number

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;
}

Categories

Resources