简体   繁体   English

F#-代码改进

[英]F# - Code improvement

i'm new to F# and i've come up with a solution to a fairly simple question, which is, given a string of numbers, I need to multiple each digit by two, then get the sum of these digits. 我是F#的新手,我想出了一个相当简单的问题的解决方案,即给定一串数字,我需要将每个数字乘以2,然后得到这些数字的总和。 For example, the string "123456" should equate to 24 例如,字符串“ 123456”应等于24

Here is what I was able to come up with 这就是我想出的

let input = "123456"
        |> Seq.map (string >> int)
        |> Seq.map (fun(x) -> x * 2)
        |> Seq.map (int >> string)
        |> String.concat String.Empty
        |> Seq.map (string >> int)
        |> Seq.sum

My question is, is there any substantial changes I could make, to make my solution more condensed and more efficient? 我的问题是,我可以做一些实质性的改变来使我的解决方案更简洁,更有效吗? Any help will be greatly appreciated 任何帮助将不胜感激

You can compact your code by applying some properties. 您可以通过应用一些属性来压缩代码。

fun x -> x * 2 is fun x -> x * 2

fun x -> (*) x 2 (operator as a function) fun x -> (*) x 2 (运算符作为函数)

fun x -> (*) 2 x (commutative) fun x -> (*) 2 x (可交换)

(*) 2 (eta-reduction) (*) 2 (减少eta)

map composition is the same as the composition of the functions to map, your first 3 maps could be written as: map组成与要映射的函数的组成相同,您的前三个map可以写为:

Seq.map (string >> int >> (*) 2 >> string)

map and then concat is collect map ,然后collect concat

map and then sum is sumBy map ,然后sumsumBy

So your code could be: 因此,您的代码可能是:

"123456"
    |> String.collect (string >> int >> (*) 2 >> string)
    |> Seq.sumBy (string >> int)

I understand that this might be a toy example, but I think that it is actually quite hard to write it in a readable way. 我知道这可能是一个玩具示例,但我认为以可读的方式编写它实际上非常困难。 I had to run your code line-by-line before I actually understood what is going on! 在我真正了解发生了什么之前,我必须逐行运行您的代码!

You can definitely contract it into quite short expression using point-free style (as Gustavo's answer shows), but I would probably not go that far - because you might need to be able to read & understand the code later! 您绝对可以使用无点样式将其压缩为很短的表达式(如Gustavo的答案所示),但是我可能不会走得那么远-因为您以后可能需要阅读和理解代码!

An alternative way would be to use sequence expressions and write something like this: 另一种方法是使用序列表达式并编写如下内容:

[ for c in "123456" do
    // Get the number, multiply it & yield its characters
    let number = int (string c)
    yield! string (number * 2) ]
// Sum the numbers (converting char to int via a string)
|> Seq.sumBy (string >> int)

This is a bit shorter than your original version, but it is still (I think) fairly understandable. 这比您的原始版本短一些,但是(我认为)仍然可以理解。

In terms of efficiency, instead of converting each character in the string into a string in its own right just so you can then convert it to an int... 就效率而言,与其直接将字符串中的每个字符转换成字符串,不如将其转换为整数。

|> Seq.map (string >> int)

I would convert the character directly to a number: 我将字符直接转换为数字:

|> Seq.map (Char.GetNumericValue >> int)

This results in less garbage to collect, and although I haven't benchmarked it, I would expect it to be faster. 这样可以减少收集的垃圾,尽管我尚未对其进行基准测试,但我希望它会更快。

Like Tomas commented I've not considered the digit-requirement in my original post. 就像Tomas所说的那样,我在原始帖子中没有考虑过数字的要求。 So heres my corrected version: 所以这是我的更正版本:

"123456"
  |> Seq.map    (string >> int)        // Convert to int sequence
  |> Seq.collect(fun x -> string(x*2)) // Perform multiplication, 
                                       // convert to string and collect the digits as chars
  |> Seq.sumBy  (string >> int)        // Convert the chars to string and than to integer 
                                       // to sum them correctly

It is more or less the same what Gustavo posted. 古斯塔沃发布的内容大致相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM