Custom order by, is it possible? - c#

I have the following collection:
-3, -2, -1, 0, 1, 2, 3
How can I in a single order by statement sort them in the following form:
The negative numbers are sorted first by their (absolute value) then the positive numbers.
-1, -2, -3, 0, 1, 2, 3

Combination sorting, first by the sign, then by the absolute value:
list.OrderBy(x => Math.Sign(x)).ThenBy(x => Math.Abs(x));
or:
from x in list
orderby Math.Sign(x), Math.Abs(x)
select x;
This is conceptually similar to the SQL statement:
SELECT x
FROM list
ORDER BY SIGN(x), ABS(x)
In LINQ-to-Objects, the sort is performed only once, not twice.
WARNING: Math.Abs(x) will fail if x == int.MinValue. If this marginal case is important, then you have to handle it separately.

var numbers = new[] { -3, -2, -1, 0, 1, 2, 3 };
var customSorted = numbers.OrderBy(n => n < 0 ? int.MinValue - n : n);
The idea here is to compare non-negative numbers by the value they have. And compare negative numbers with the value int.MinValue - n which is -2147483648 - n and because n is negative, the higher negative number we, the lower negative result the outcome will be.
It doesn't work when the list itself contains the number int.MinValue because this evaluates to 0 which would be equal to 0 itself. As Richard propose it could be made with longĀ“s if you need the full range but the performance will be slightly impaired by this.

Try something like (VB.Net example)
Orderby(Function(x) iif(x<0, Math.Abs(x), x*1000))
...if the values are <1000

You could express it in LINQ, but if I were reading the code two years later, I'd prefer to see something like:
list.OrderBy(i=>i, new NegativeThenPositiveByAscendingAbsoluteValueComparer());
You will need to implement IComparer.

Related

Where(i => i % 2 == 0)

I'm currently learning about PLINQ (Parallel Language Integrated Query) on Visual Studio 2012's C#.
In the one lesson Where(i => i % 2 == 0) was given to me, but I've no idea what it means and the book i'm studying from didn't give any explanation.
Does anyone know what this means?
First hope you know % which is "The % operator computes the remainder after dividing its first operand by its second". Read more about % Operator
if you have a list of numbers
var list = new List<Int32>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
var result = list.Where(i => i%2 == 0);
So the result will have 2,4,6,8 and 10.
Same thing can be written as
var ans = new List<Int32>();
foreach (var an in list)
{
if (an%2 == 0)
ans.Add(an);
}
The query is selecting only even numbers, where division by 2 has no remainder.
The % operator computes the remainder after dividing its first
operand by its second. All numeric types have predefined remainder
operators.
http://msdn.microsoft.com/en-us/library/0w4e0fzs.aspx
lambda expressions are a bit weird at 1st however when you experiment a bit in VS (and its intellisense) you'll get used to it in no time. as soon as you type in "i=>" you declare a range variable of your type of object which implements IEnumerable(<T>) interface. In this case i is one element of your list (or other IEnumerable>> list, dictionary....) to investigate this case you search for even numbers...
Let's say this is the case:
List<int> source = new List<int>() { 1, 2, 3, 4 };
var evenNumbers = source.Where(i => i % 2 == 0);
Where is filtering source and returning only it's even numbers.
Where is a Linq extension method that works on any object implementing the IEnumerable interface (likeList).
i => i % 2 == 0 is a lambda expression. In this case it means that for each item i in source, Where will apply the expression i % 2 == 0.
Where selects the items in source for which the lambda expression is true. In this case, the expression is true when i is an even number.
This is because of the modulo operator %, which returns the remainder of the integer division between two numbers a and b: a % b. If a = 4 and b = 3, then a % b values 1, because it is what remains when dividing 4 by 3. If % returns 0, then it means that a is divided by b. If b is 2, then it means that a is even.
Where(i => i % 2 == 0)
it means i goes to where i % 2 == 0 that is if
you are doing it for a list of integer it will return all even numbers from list

C# formula to determine index

I have a maths issue within my program. I think the problem is simple but I'm not sure what terms to use, hence my own searches returned nothing useful.
I receive some values in a method, the only thing I know (in terms of logic) is the numbers will be something which can be duplicated.
In other words, the numbers I could receive are predictable and would be one of the following
1
2
4
16
256
65536
etc
I need to know at what index they appear at. In othewords, 1 is always at index 0, 2 at index 1, 4 at index 3, 16 is at index 4 etc.
I know I could write a big switch statement but I was hoping a formula would be tidier. Do you know if one exists or any clues as the names of the math forumula's I'm using.
The numbers you listed are powers of two. The inverse function of raising a number to a power is the logarithm, so that's what you use to go backwards from (using your terminology here) a number to an index.
var num = 256;
var ind = Math.Log(num, 2);
Above, ind is the base-2 logarithm of num. This code will work for any base; just substitute that base for 2. If you are only going to be working with powers of 2 then you can use a special-case solution that is faster based on the bitwise representation of your input; see What's the quickest way to compute log2 of an integer in C#?
Try
Math.Log(num, base)
where base is 2
MSDN: http://msdn.microsoft.com/en-us/library/hd50b6h5.aspx
Logarithm will return to You power of base from you number.
But it's in case if your number really are power of 2,
otherwise you have to understand exactly what you have, what you need
It also look like numbers was powered to 2 twice, so that try this:
private static int getIndexOfSeries(UInt64 aNum)
{
if (aNum == 1)
return 0;
else if (aNum == 2)
return 1;
else
{
int lNum = (int)Math.Log(aNum, 2);
return 1+(int)Math.Log(lNum, 2);
}
}
Result for UInt64[] Arr = new UInt64[] { 1, 2, 4, 16, 256, 65536, 4294967296 } is:
Num[0] = 1
Num[1] = 2
Num[2] = 4
Num[3] = 16
Num[4] = 256
Num[5] = 65536
Num[6] = 4294967296 //65536*65536
where [i] - index
You should calculate the base 2 logarithm of the number
Hint: For the results:
0 2
1 4
2 16
3 256
4 65536
5 4294967296
etc.
The formula is, for a give integer x:
Math.Pow(2, Math.Pow(2, x));
that is
2 to the power (2 to the power (x) )
Once the formula is known, one could solve it for x (I won't go through that since you already got an answer).

Accurate behavior of the sort method in C#?

static void Main()
{
var array = new[] {1, 2, 3, 4, 5};
Array.Sort(array, (x, y) => x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1);
array.ToList().ForEach(Console.WriteLine);
}
The output result is 3,5,1,2,4.
According to my understanding, in the sort delegate: Odd numbers equal odd numbers; Even number equal even numbers; Odd numbers are before even numbers. Why the output is not 1,3,5,2,4? Thanks.
From MSDN:
Array.Sort uses the QuickSort algorithm. This implementation performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.
You are just comparing even and odd in your comparer function. Like the others said, quicksort is non-stable. Why not add an additional check for value in addition to even/odd when the values are both either even or odd.
// if x odd and y even return -1
// else if x even and y odd return 1
// else return x.CompareTo(y)
Array.Sort(array, (x, y) => x % 2 == y % 2 ? x.CompareTo(y) : x % 2 > y % 2 ? -1 : 1);

Algorithm for sum of integers [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding all possible combinations of numbers to reach a given sum
I have to create method which from array of numbers selects numbers, which sum will be exact as required one or if such doesn't exist select the minimal greater one.
What would be the algorithm of this function?
public int[] selectExactSum(int[] X, int SUM) {
}
example:
numbers are: {5, 2, 8, 4, 6} and required sum is 12.
The result would be: {2, 4, 6}
If required sum is 13, the result would be:{2, 8, 4} - so, the sum would be in this case 14 - the first minimal greater one.
If Required sum is 15, the possible results would be: {5, 2, 8} or {5, 4, 6}. In this case return the one of your choice - probably the first one you get.
What would be the algorithm for custom numbers and sum?
Thanks,
Simon
This is a generalized case of the problem called subset sum. It's an NP-complete problem, thus the best known algorithm is pseudo-polynomial.
If you understand the above linked algorithm, you can deduct the modification necessary to solve your problem.
How about recursively?
public static int[] SelectExactSum(int[] x, int sum) {
int[]
rest = x.Skip(1).ToArray(),
with = x.Length == 1 ? x : x.Take(1).Concat(SelectExactSum(rest, sum - x[0])).ToArray(),
without = x.Length == 1 ? new int[0] : SelectExactSum(rest, sum);
int withSum = with.Sum(), withoutSum = without.Sum();
return
withSum >= sum ? (withoutSum >= sum ? (withSum < withoutSum ? with : without) : with) :
withoutSum >= sum ? without : new int[0];
}
Note: Calling SelectExactSum(new int[] {5,2,8,4,6}, 13) doesn't return {2,8,4} as stated in the question, but {5,8} as that actually sums up to 13.
Took me about 15 minutes to made it, you can see it running here:
http://jesuso.net/projects/selectExactSum/index.php?numbers=5%2C2%2C8%2C4%2C6&reqSum=15
And here's the code:
http://jesuso.net/projects/selectExactSum/selectExactSum.txt
I made it as simple as possible, but its made on PHP, let me know if you need some help translating it to c#.

How do I order an array of floating point numbers using a criteria other than size, using LINQ?

For example, I have an array of floating point numbers:
float[] numbers = new float[] { 1, 34, 65, 23, 56, 8, 5, 3, 234 };
If I use:
Array.Sort(numbers);
Then the array is sorted by the size of the number.
I want to sort the numbers by another criteria, so element A should go before element B if f(A) < f(B), rather than the usual of A < B.
So, for example, If I want to sort them according to there value modulo 5. The array would become:
5, 65, 1, 56, 3, 8, 23, 34, 234
I think it can be done through LINQ, but I'm not sure how.
I want to sort the numbers by another criteria, so element A should go before element B if f(A) < f(B)
numbers.OrderBy(f);
You can use the Comparison<T> overload of Array.Sort:
Array.Sort(numbers, (a,b) => (a % 5).CompareTo(b % 5));
Comparison<T> is just a delegate, so you can use lambdas / anonymous methods. It's not LINQ, but I think it's what you meant.
Using LINQ:
var result = from n in numbers orderby n % 5, n select n;
var sortedNumbers = result.ToArray();
Alternately:
var result = numbers.OrderBy(n => n % 5).ThenBy(n => n);
Ordering by mod 5, then by the number yields the results in the order you specified.
Have a look at IComparer ;-) and let an List sort the elements for you with your custom comparer.
More Brute even! I suggest you to make an Array of f(x) and then sort on that!

Categories

Resources