首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >F#:什么叫地图和折叠的组合,或者地图和缩减的组合?

F#:什么叫地图和折叠的组合,或者地图和缩减的组合?
EN

Stack Overflow用户
提问于 2021-11-28 09:41:30
回答 2查看 192关注 0票数 2

一个受这个问题启发的简单示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module SimpleExample =
    let fooFold projection folder state source =
        source |> List.map projection |> List.fold folder state
    // val fooFold :
    //   projection:('a -> 'b) ->
    //     folder:('c -> 'b -> 'c) -> state:'c -> source:'a list -> 'c

    let fooReduce projection reducer source =
        source |> List.map projection |> List.reduce reducer
    // val fooReduce :
    //   projection:('a -> 'b) -> reducer:('b -> 'b -> 'b) -> source:'a list -> 'b

    let game = [0, 5; 10, 15]
    let minX, maxX = fooReduce fst min game, fooReduce fst max game
    let minY, maxY = fooReduce snd min game, fooReduce snd max game

在这个例子中,函数fooFoldfooReduce的自然名称是什么?唉,mapFoldmapReduce已经被录取了。

mapFold是F#库的一部分,对输入执行fold操作以返回与scan类似的'result list * 'state元组,但不需要自己提供元组作为状态的一部分。它的签名是:

val mapFold:('State -> 'T -> 'Result * 'State) -> 'State -> 'T list -> 'Result list * 'State

由于投影可以很容易地集成到文件夹中,因此只为说明目的而包含fooFold函数。

MapReduce

MapReduce是一种使用大量节点处理某些可分布问题的庞大数据集的算法。

现在,对于一个更复杂的例子,fold/reduce不是直接应用于输入,而是应用于所选键后面的分组。这个例子是从Python库借来的,在那里它被称为--也许是误导-- reduceby

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module ComplexExample =
    let fooFold keySelection folder state source =
        source |> Seq.groupBy keySelection 
        |> Seq.map (fun (k, xs) ->
            k, Seq.fold folder state xs) 
    // val fooFold :
    //   keySelection:('a -> 'b) ->
    //     folder:('c -> 'a -> 'c) -> state:'c -> source:seq<'a> -> seq<'b * 'c>
    //     when 'b : equality

    let fooReduce keySelection projection reducer source =
        source |> Seq.groupBy keySelection 
        |> Seq.map (fun (k, xs) ->
            k, xs |> Seq.map projection |> Seq.reduce reducer) 
    // val fooReduce :
    //   keySelection:('a -> 'b) ->
    //     projection:('a -> 'c) ->
    //     reducer:('c -> 'c -> 'c) -> source:seq<'a> -> seq<'b * 'c>
    //     when 'b : equality

    type Project = { name : string; state : string; cost : decimal }
    let projects =
        [ { name = "build roads";  state = "CA"; cost = 1000000M }
          { name = "fight crime";  state = "IL"; cost = 100000M  }
          { name = "help farmers"; state = "IL"; cost = 2000000M }
          { name = "help farmers"; state = "CA"; cost = 200000M  } ]
    fooFold (fun x -> x.state) (fun acc x -> acc + x.cost) 0M projects
    // val it : seq<string * decimal> = seq [("CA", 1200000M); ("IL", 2100000M)]

    fooReduce (fun x -> x.state) (fun x -> x.cost) (+) projects
    // val it : seq<string * decimal> = seq [("CA", 1200000M); ("IL", 2100000M)]

这里的函数fooFoldfooReduce的自然名称是什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-28 14:33:50

我可能会将前两个名称称为mapAndFoldmapAndReduce (虽然我同意,如果mapFoldmapReduce还没有被使用的话,它们将是好名字)。或者,我会使用mapThenFold (等),这可能更明确,但它读起来有点麻烦。

对于更复杂的问题,reduceByfoldBy听起来不错。问题是,如果您还想要那些不执行映射操作的函数的版本,这是行不通的。如果您想这样做,您可能需要mapAndFoldBymapAndReduceBy (以及foldByreduceBy)。这有点难看,但恐怕这是你能做的最好的了。

更普遍的问题是,当将名称与Python进行比较时,Python允许重载,而F#函数则不允许重载。这意味着您需要对具有多个重载的函数有一个唯一的名称。这意味着您只需要想出一个一致的命名方案,不会让名字长得让人难以忍受。

(我在为Deedle图书馆中的函数命名时经历了这种情况,这在某种程度上是受到Pandas的启发。例如,您可以看到Deedle中的聚集函数作为一个例子--在命名中有一个模式来处理每个函数都需要一个唯一的名称。)

票数 1
EN

Stack Overflow用户

发布于 2021-11-29 16:55:46

作为托马斯,我有不同的看法。

首先,我认为没有重载是件好事,给每个操作都取唯一的名称也是件好事。我还要说,给很少使用的函数取长名称更重要,不应回避。

编写较长的名称通常不会成为问题,因为我们作为编程人员通常使用具有自动完成功能的IDE。但是阅读和理解是不同的。因为一个长的描述性名称而知道一个函数所做的事情比一个短的名称更好。

较长的描述函数名越重要,使用函数的频率就越小。它有助于阅读和理解代码。很少使用的简短和较少描述性的函数名会引起混淆。如果它仅仅是另一个函数名的过载,那么混乱就会增加。

是的,命名事物可能很难,这就是为什么它的重要性和不可回避的原因。

和你描述的一样。我会给它取名为mapFoldmapReduce。就像他们所做的那样。

在F#中已经有了一个F#,在我看来,F#开发人员要么将函数的命名、参数或输出搞砸了。但不管怎样,他们都搞砸了。

我通常会期望mapFoldmap,然后做fold。实际上是这样,但它也返回在运行过程中创建的中间列表。我不希望它回来的东西。我也希望它能传递两个函数而不是一个函数。

当我们谈到托马斯关于命名它的建议时,mapAndFoldmapThenFold。那么,我希望这两种功能有不同的行为。mapThenFold准确地告诉了它所做的事情。map,然后fold在上面。我认为并不重要。这也是为什么我会把它命名为mapFoldmapReduce。用这种方式编写它已经建议使用,然后是

但是mapAndFoldmapAndReduce并没有透露执行顺序。它只是说它做了两件事,或者以某种方式返回这个

考虑到这一点,我想说的是,F#库应该将其mapFold命名为mapAndFoldmapAndFold,将返回值更改为只返回折叠(并且有两个参数而不是一个参数)。但是,现在一切都搞砸了,我们不能再改变了。

至于mapReduce,我认为你有点弄错了。mapReduce算法就是这样命名的,因为它只执行mapreduce。就是这样。

但是,使用其无状态和更具描述性的操作进行函数式编程有时会带来额外的好处。从技术上讲,map的功能不如for/fold,因为它只是描述了值是如何改变的,而不是顺序或列表中的位置。但是由于这个限制,您可以并行运行它,甚至可以在大型计算机集群上运行。这就是你引用的mapReduce算法。

但这并不意味着mapReduce必须始终在大型集群上或并行地运行其操作。在我看来,你可以把它命名为mapReduce,这很好。每个人都会知道它的作用,我认为没有人期望它会突然在集群上运行。

总的来说,我认为F#提供的F#是愚蠢的,下面是我认为应该提供的4个例子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let double x = x * 2
let add x y  = x + y

mapFold      double add 0 [1..10] // 110
mapAndFold   double add 0 [1..10] // [2;4;6;8;10;12;14;16;18;20] * 110
mapReduce    double add   [1..10] // Some (110)
mapAndReduce double add   [1..10] // Some ([2;4;6;8;10;12;14;16;18;20] * 110)

好吧,mapFold不是这样工作的,所以您有以下选项。

  1. 按照您的方式实现mapReduce。忽略与mapFold的一致性。
  2. 提供mapAndReducemapReduce
  3. 让您的mapReduce返回与mapFold的默认实现相同的废话,并提供mapThenReduce
  4. 喜欢(3),还添加了mapThenFold

选项4对F#中已经存在的内容具有最大的兼容性和期望值。但这并不意味着你必须那样做。

在我看来,我只是:

  1. 实现mapReduce,返回映射的结果,然后减少
  2. 我不关心返回列表和结果的mapAndReduce版本。
  3. 提供一个mapThenFold,它需要两个函数参数,返回折叠的结果。

请注意:只通过调用mapReduce然后调用reduce就实现了reduce,这有点毫无意义。我希望它有一个更低级别的实现,只需遍历一次数据结构就可以做到这两件事。如果没有,我只需打电话给map,然后再调用reduce

因此,实现应该如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let mapReduce mapper reducer xs =
    let rec loop state xs =
        match xs with
        | []    -> state
        | x::xs -> loop (reducer state (mapper x)) xs
    match xs with
    | []    -> ValueNone
    | [x]   -> ValueSome (mapper x)
    | x::xs -> ValueSome (loop (mapper x) xs)

let double x = x * 2
let add x y  = x + y

let some110 = mapReduce double add [1..10]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70145934

复制
相关文章
C#如何删除字符串中任何位置的空格?
你或许知道你能使用String.Trim()方法,去除字符串的头和尾的空格。不幸运的是,这个Trim方法不能去除字符串中间的C#空格。
高一峰
2020/09/22
11.8K0
C#如何删除字符串中任何位置的空格?
JavaScript 中获取光标位置
DOM中并没有直接获取光标位置的方法,那么我们只能间接来获取光标位置。DOM支持获取光标选中的范围,我们可以以此为切入点,来获取或定位光标的位置,当选取范围起始点和结束点一样时,就是光标插入的位置。
越陌度阡
2020/11/26
12.5K0
mysql 从json字符串中获取指定的key:
SELECT SUBSTR(detail,    LOCATE('"email"',detail)+LENGTH('"email":"'),    LOCATE('",', detail,LOCATE('"email"',detail))-(LOCATE('"email"',detail)+LENGTH('"email":"'))) AS email FROM tb_sync_moka2oa_full_detail where moka_id in ( 62923,    64242,    66971,    67197,    67198,    67304,    74124) and is_delete = 0 order by id desc limit 50  ; 虽然mysql 5.7之后支持 JSON_EXTRACT 了,我测试了下好像不行
凯哥Java
2022/12/16
7.4K0
Flutter 中获取地理位置[Flutter专题11]
如今,发现用户位置是移动应用程序非常常见且功能强大的用例。如果您曾经尝试过在 Android 中实现位置,您就会知道样例代码会变得多么复杂和混乱。
徐建国
2021/11/30
3.3K0
Flutter 中获取地理位置[Flutter专题11]
后端 | Java 利用substring()和indexOf()从字符串中获取指定的字符
代码: @Test void spiltStrDemo() { /* * str.substring(4, 9); -->在str中截取从下标4开始(包含),到下标9之间的字符(不包含9) * str.indexOf("/"); -->返回str中“/”第一次出现时的下标 * str.indexOf("/", 5); -->返回跳过str的前6个字符后,“/”第一次出现的下标。可以利用这个方法跳过前几个相同的字符
倾盖
2022/08/16
3.2K0
后端 | Java 利用substring()和indexOf()从字符串中获取指定的字符
Flutter中的获取设备信息以及获取地理位置
在使用之前,我们一定要好好阅读文档,关于Android以及iOS平台的相关配置,我在这里不做过多介绍,大家自己去看文档。
拉维
2019/09/10
12.3K0
【已解决】怎么获取字符串中相同字符串第N 个所在的位置
对于我们经常用的rangeOfString这个方法只能获取最近的一次出现的位置,而不能指定第几个出现的位置。
君赏
2018/09/07
2.5K0
替换字符串指定位置字符 php,php如何从指定位置替换字符串
在php中可以使用“substr_replace”函数实现从指定位置替换字符串,其语法是“substr_replace(string,replacement,start,length)”,参数start表示从指定位置开始替换。
全栈程序员站长
2022/08/31
3.6K0
替换字符串指定位置字符 php,php如何从指定位置替换字符串
C#中获取系统时间
static void Main(string[] args) { Console.WriteLine("获取日期加时间:"); string strDateandTime = DateTime.Now.ToString(); Console.WriteLine(strDateandTime); Console.WriteLine("获取日期:");
牛老师讲GIS
2018/10/23
4.2K0
C#中获取系统时间
C#学习---基础入门(四)C#中的字符与字符串
字符 char(单个字符) 用单引号 ,例如char a=‘a’;可以通过调用char类下的方法进行一些操作,具体通过help查看其相关方法
互联网CEO
2018/12/03
7940
C# 文本框 TextChanged 延时触发
public partial class DelayTextBox : TextBox { #region private globals private System.Timers.Timer DelayTimer; // used for the delay private bool TimerElapsed = false; // if true OnTextChanged is fired. private bool Key
跟着阿笨一起玩NET
2019/03/14
2K0
C#的WinForm窗体程序中如何设置TextBox为密码文本框
在C#的WinForm窗体程序开发过程中,TextBox是常用的文本框控件,默认的TextBox文本 框输入的内容是可见的,如果在Winform程序中要设置TextBox文本框为密码输入框应该如何设置呢?其实将TextBox文本框设置为密码输入 框,也非常的简单,只需要设置TextBox文本框属性中的PasswordChar属性值,PasswordChar属性值自定义,可以为*号,代表输 入字符显示星号,也可为其他自定义字符。
全栈程序员站长
2022/09/07
5.6K0
C#中字符,字符串的大小写转换
对字符串来说,"string".ToLower()和"string".ToUpper()可以基本满足需求,但是当需要将首字母大写的时候,这两个函数就有点不够用了.但还好,我们还有TextInfo类下的ToLittleCase方法.在使用TextInfo类时,必须指定区域性.要获得区域性,必须能够访问当前线程,从该线程中检索CurrentCulture属性.
望天
2018/08/02
2.3K0
从损坏的手机中获取数据
有时候,犯罪分子会故意损坏手机来破坏数据。比如粉碎、射击手机或是直接扔进水里,但取证专家仍然可以找到手机里的证据。
FB客服
2020/02/23
10.2K0
getBoundingClientRect方法获取元素在页面中的相对位置
获取元素位置可以用 offset 或 getBoundingClientRect,使用 offset 因为兼容性不好,比较麻烦,offset获取位置会形成“回溯”。而 getBoundingClientRect 方法则 兼容性较好,基本所有的浏览器都支持了,且使用起来更容易和简单。
用户6167509
2019/09/04
3.9K0
什么?RecyclerView中获取点击位置的接口被废弃了?
《第三行代码》这才刚刚出版,竟然就有API被弃用了,我决定对这个问题好好研究一下,并加急写一篇文章进行分析。
用户1158055
2020/04/24
4.5K0
什么?RecyclerView中获取点击位置的接口被废弃了?
通过IP获取位置
昨天写了个获取天气的API,那么我也该写一个调用这个API的Demo了。不过获取天气必须要城市名称,而Demo上不可能在弄一个输入城市的吧……好在,可以通过IP获取所在城市。 <?php if(iss
FHYC
2018/06/22
1.8K0
[译]C#和.NET中的字符串
原文地址:Jon Skeet:Strings in C# and .NET System.String 类型(在C#语言中对应的别名是string)是.NET最重要的类型之一,不幸的是在它身上存在了太
潘成涛
2018/01/18
2.5K0
VBA代码库08:获取字符串中指定位置的子字符串
下面的自定义函数:ExtractString函数,来源于《VBA Developer’s Handbook》,对于分析字符串来说,是一个很有用的函数。
fanjy
2019/09/19
3.4K0
VBA代码库08:获取字符串中指定位置的子字符串
获取地理位置
可根据获取到的经纬度查询到所在的地理位置。 <p><button onclick="geoFindMe()">Show my location</button></p> <div id
ProsperLee
2018/10/24
2K0
获取地理位置

相似问题

火场动态链接与世博会

11

是否有一种方法可以显式分离隐式链接的DLL?

13

是否有一种方法可以检查Dropbox中的文件/文件夹是否有共享链接而不创建链接?

10

是否有一种方法可以撤消分离的头状态,而不取消我在分离头状态中所做的工作?

17

是否有一种方法可以强迫浏览器加载链接而不访问缓存?

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文