【问题标题】:Array 'map' vs 'forEach' - functional programming数组 'map' 与 'forEach' - 函数式编程
【发布时间】:2018-10-24 08:56:23
【问题描述】:

我有一个对象数组:

let reports = [{ inbound_calls: [...], outbound_calls: [...],  outbound_national_calls: [...] },...];

创建新数组并赋值给变量的最佳方法是什么:

第一种方法 - 一个循环:

let inbound_calls = []; outbound_national_calls = [], outbound_calls = [];

reports.forEach((e) => {
 inbound_calls.push(e.inbound_calls);
 outbound_national_calls.push(e.outbound_national_calls);
 outbound_calls.push(e.outbound_calls);
})

第二种方法:

let inbound_calls = this.reports.map((report) => report.inbound_calls)
let outbound_national_calls = this.reports.map((report) => report.outbound_national_calls)
let outbound_calls = this.reports.map((report) => report.outbound_calls)

我开始学习函数式编程,并想将其应用到我的代码中,我会采用第一种方法(一个循环),但是当我对函数式编程进行研究时,我认为第二种方法是正确的(更清洁)但是,我不确定,什么是更便宜的操作?

【问题讨论】:

  • forEach() 循环将是成本较低的操作。如果性能是绝对必要的,那么传统的for() 循环是 JS 运行时中最快的循环。
  • @MátéSafranka 是的。从技术上讲,使用此代码,最简单的事情就是执行inbound_calls = reports.inboundCalls.slice()。但是,我认为这个问题仍然有可取之处,如果reports 包含类似[ { inbound_calls: ...} ] 的内容可能会更有意义

标签: javascript dictionary functional-programming


【解决方案1】:

如果您的最终目标是从对象中创建三个变量,您可以使用对象解构,如下所示。不需要循环。

let reports = {
  inbound_calls: [1, 2, 3],
  outbound_calls: [4, 5, 6],
  outbound_national_calls: [7, 8, 9]
};

let {inbound_calls, outbound_calls, outbound_national_calls} = reports;
console.log(inbound_calls);
console.log(outbound_calls);
console.log(outbound_national_calls);

【讨论】:

  • 目前成本最低的手术!很好的答案。
  • 请注意,这不会复制数组。对变量的任何突变也会使原始数组发生突变。
  • @ibrahimmahrir -- OP 编码的内容是一样的。 OP 没有提到他想创建副本的任何地方。不过,如果需要副本,显然首选使用slice
  • @31piy 不,它没有。无论如何,OP的代码都是错误的。 OP也显然打算复制这些项目。不确定这是否真的是他想要的,但不确定他的代码的目标是什么。
  • 谢谢你,但我的问题报告中有错误是数组,所以我不能在那里使用这样的破坏......
【解决方案2】:

如果您想复制数组,只需使用Array#slice(传递的0 是可选的,因为它是默认的起始索引,因此您可以根据需要省略它),例如:

let inbound_calls = reports.inbound_calls.slice(0),
    outbound_national_calls = reports.outbound_national_calls.slice(0), 
    outbound_calls = reports.outbound_calls.slice(0);

Array.from 喜欢:

let inbound_calls = Array.from(reports.inbound_calls),
    outbound_national_calls = Array.from(reports.outbound_national_calls), 
    outbound_calls = Array.from(reports.outbound_calls);

【讨论】:

  • 您不需要将0 提供给.slice() - 这是默认值。不带参数调用它就足够了。
  • @vlaz 对。我已经添加了一个关于它的注释。我仍然认为提供它更好,因为它更清晰。
  • 我明白你的意思。我确实曾经这样做过,但在某些时候我停止了。我绝对可以看到任何一种调用方式的优点。一开始我这样做是因为其他东西需要一个开始参数,而且总是将它提供给.slice() 对我来说不会那么混乱。后来,我在做了其他事情后回到了 JS,实际上我有一段时间忘记添加索引,直到我遇到了一些旧代码。无论哪种方式都不是什么大问题,所以只要你保持一致,就可以了。
【解决方案3】:

您实际上在做的是矩阵转置:

const report = (inbound_calls, outbound_calls, outbound_national_calls) =>
    ({ inbound_calls, outbound_calls, outbound_national_calls });

const reports = [report(1,2,3), report(4,5,6), report(7,8,9)];

const transpose = reports =>
    report( reports.map(report => report.inbound_calls)
          , reports.map(report => report.outbound_calls)
          , reports.map(report => report.outbound_national_calls) );

console.log(transpose(reports));

现在,根据您的应用程序,转置矩阵的最快方法可能是根本不转置它。例如,假设您有一个矩阵A 及其转置B。然后,它对所有索引 ijA[i][j] = B[j][i] 都成立。考虑:

const report = (inbound_calls, outbound_calls, outbound_national_calls) =>
    ({ inbound_calls, outbound_calls, outbound_national_calls });

const reports = [report(1,2,3), report(4,5,6), report(7,8,9)];

// This is equivalent to transpose(reports).outbound_calls[1]
const result = reports[1].outbound_calls;

console.log(result);

话虽如此,您的第二种方法是恕我直言,最易读。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-12
    • 1970-01-01
    相关资源
    最近更新 更多