Reputation: 3332
in a different SO question it was asked to get a signed integer reversed digit-wise: 123 becomes 321 and -123 becomes -321
this is an obvious, quite readable implementation:
int reverse (int i) {
int sign = i/Math.Abs(i);
var abs = string.Concat(Math.Abs(i).ToString().Reverse());
return int.Parse(abs)*sign;
}
this more compact LINQ expression was also suggested: .ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
but I do not understand the results of the latter:
int j = -123;
int a = j.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
int b = -(123.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0'));
int c = -123.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
int d = -(123).ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
Console.WriteLine($"{a} , {b} , {c} , {d}");
results in
3207 , -321 , -321 , -321
why does it only work with a literal int? whats is my fallacy, what do I assume wrongly?
Upvotes: 0
Views: 108
Reputation: 6749
With a
you're starting with -123
but with the others you're starting with 123
and making the result -
.
(-123)
Check it out.
using System;
using System.Linq;
public class Program
{
public static void Main()
{
int j = -123;
int a = j.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
int b = -(123.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0'));
int c = -123.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
int d = -(123).ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
//Make -123 like line below.
int e = (-123).ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
Console.WriteLine($"{a} , {b} , {c} , {d}, {e}");
Console.ReadKey();
}
}
//OUTPUTS
//3207 , -321 , -321 , -321, 3207
I answered above why you weren't getting the proper results with the method but I did not answer how it could be achieved. For now I concur with you; "there is not nice LINQ expression for this". However; I was able to turn it into a decently readable one line of code that became a beautiful looking extension method.
I did take a look at the comments below the question and I borrowed from Falco Alexander's comment to use Math.Sign
a feature I didn't know existed honestly. I was going to do it manually with a if x < 0 return result * -1
sorta deal.
I also noticed an issue with the current Aggregate
function being used and that's that it doesn't support decimals. Currently it's only int
but I took it up a notch and tried with double
as well. To add the decimal point I aggregated a string
; but then I assumed aggregating a string is a bad thing since we only want to perform string computations as little as possible and just made a new string
(which breaks the inline LINQ look but performs much better I'm assuming) Anyway; I ended up with what you see below, almost identical to what you have, but working negatives and decimals.
using System;
using System.Linq;
public class Program
{
public static void Main()
{
int j = -123;
int k = 123;
double l = -123.456;
double m = 123.456;
Console.WriteLine(j.Reverse());
Console.WriteLine(k.Reverse());
Console.WriteLine(l.Reverse());
Console.WriteLine(m.Reverse());
Console.ReadKey();
}
}
public static class Extensions
{
public static int Reverse(this int value)
{
return Math.Sign(value) * int.Parse(new string(Math.Abs(value).ToString().Reverse().ToArray()));
}
public static double Reverse(this double value)
{
return Math.Sign(value) * double.Parse(new string(Math.Abs(value).ToString().Reverse().ToArray()));
}
}
//OUTPUTS
//-321
//321
//-654.321
//654.321
Upvotes: 2
Reputation: 13676
The reason is that in all cases except for a
the int
converted to string
is "123" and not "-123". The minus sign is applied to the result of execution and not used in a .ToString
call
In this expression:
-123.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0')
The .ToString()
will be called on "123" and then the rest of LINQ query is executed with Aggregate returning int
and only then the minus sign will be applied to resulting int number. An illustration of it would be:
-1 * 123.ToString().Reverse().Aggregate(...)
Even this expression:
int d = -(123).ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');
Will be transformed to something like:
int d = -1 * (123).someExpr
First compiler removes redundant parentheses, then executes expression and at last it changes the sign of result to minus
P.S.
As @PetSerAI correctly pointed out you could modify LINQ expression to make it work as follows:
int d = Math.Sign(j) * Math.Abs(j).ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0')
Upvotes: 3