LINQ表达式在文字上的表现不同吗?

时间:2018-12-08 17:07:02

标签: c# linq

在一个不同的SO问题中,要求它获得一个有符号整数以数字方式反转: 123变成321并且-123变成-321

这是一个显而易见的,易读的实现:

int reverse (int i) {
    int sign = i/Math.Abs(i);
    var abs = string.Concat(Math.Abs(i).ToString().Reverse());
    return int.Parse(abs)*sign;
}

还建议使用这种更紧凑的LINQ表达式:.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');

但我不理解后者的结果:

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

结果

3207 , -321 , -321 , -321

为什么它仅适用于文字整数? 我的谬论是什么,我会错误地认为什么?

2 个答案:

答案 0 :(得分:3)

使用a时,您将从-123开始,而使用其他123时,您得到的结果是-

您需要像这样(-123)包围123

检查一下。

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

编辑

我在上面回答了为什么使用该方法无法获得正确的结果,但是我没有回答如何实现。现在我同意你的看法。 “对此没有很好的LINQ表达式”。然而;我能够将其转换为易于阅读的一行代码,成为美观的扩展方法。

我确实查看了问题下方的评论,并且从Falco Alexander的评论中借用了Math.Sign这个我不知道确实存在的功能。我本来是要通过if x < 0 return result * -1排序手动完成的。

我还注意到当前使用的Aggregate函数存在一个问题,那就是它不支持小数。目前只有int,但我想起来了,并尝试了double。要添加小数点,我汇总了string;但是后来我认为聚合字符串是一件坏事,因为我们只想尽可能少地执行字符串计算,而只是做了一个new string(这打破了内联LINQ的外观,但我认为它要好得多)。我最后得到的是您在下面看到的内容,与您所拥有的几乎相同,但是使用的是负数和小数。

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

答案 1 :(得分:3)

原因是,在所有情况下,除了a之外,转换为int的{​​{1}}都是“ 123”而不是“ -123”。负号应用于执行结果,而不在string调用中使用

在此表达式中:

.ToString

-123.ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0') 将在“ 123”上调用,然后其余的LINQ查询通过Aggregate返回.ToString()来执行,然后减号将应用于结果int数。一个例子是

int

即使这个表达式:

-1 * 123.ToString().Reverse().Aggregate(...)

将被转换为类似的内容:

int d = -(123).ToString().Reverse().Aggregate(0, (y, x) => 10 * y + x - '0');

首先编译器删除多余的括号,然后执行表达式,最后将结果的符号更改为负

P.S。

正如@PetSerAI正确指出的那样,您可以修改LINQ表达式以使其工作如下:

int d = -1 * (123).someExpr