资讯专栏INFORMATION COLUMN

计算平均值的不同实现方式

elliott_hu / 1413人阅读

摘要:本文翻译并严重删减自如果我们有以下数组需求是先过滤掉为的再计算求平均值一般想到的方法不外乎是一下几种循环可阅读性差,写法并不优雅使用分离功能代码非常干净,实际开发我们更多可能用的是这种方式使用串联的方式。

本文翻译并严重删减自five-ways-to-average-with-js-reduce/

如果我们有以下数组:需求是先过滤掉 found 为 false 的 item 再计算求平均值

const victorianSlang = [
  {
    term: "doing the bear",
    found: true,
    popularity: 108
  },
  {
    term: "katterzem",
    found: false,
    popularity: null
  },
  {
    term: "bone shaker",
    found: true,
    popularity: 609
  },
  {
    term: "smothering a parrot",
    found: false,
    popularity: null
  }
  //……
];

一般想到的方法不外乎是一下几种:

1、for 循环 (可阅读性差,写法并不优雅)

let popularitySum = 0;
let itemsFound = 0;
const len = victorianSlang.length;
let item = null;
for (let i = 0; i < len; i++) {
  item = victorianSlang[i];
  if (item.found) {
    popularitySum = item.popularity + popularitySum;
    itemsFound = itemsFound + 1;
  }
}
const averagePopularity = popularitySum / itemsFound;
console.log("Average popularity:", averagePopularity);

2、 使用 filter/map/reduce 分离功能(代码非常干净,实际开发我们更多可能用的是这种方式)

// Helper functions
// ----------------------------------------------------------------------------
function isFound(item) {
  return item.found;
}

function getPopularity(item) {
  return item.popularity;
}

function addScores(runningTotal, popularity) {
  return runningTotal + popularity;
}

// Calculations
// ----------------------------------------------------------------------------

// Filter out terms that weren"t found in books.
const foundSlangTerms = victorianSlang.filter(isFound);

// Extract the popularity scores so we just have an array of numbers.
const popularityScores = foundSlangTerms.map(getPopularity);

// Add up all the scores total. Note that the second parameter tells reduce
// to start the total at zero.
const scoresTotal = popularityScores.reduce(addScores, 0);

// Calculate the average and display.
const averagePopularity = scoresTotal / popularityScores.length;
console.log("Average popularity:", averagePopularity);

3、 使用串联的方式。第二种方式并没有什么问题,只是多了两个中间变量,在可阅读性上我还是更倾向于它。但基于Fluent interface原则(https://en.wikipedia.org/wiki...,我们可以简单改一下函数

// Helper functions
// ---------------------------------------------------------------------------------
function isFound(item) {
  return item.found;
}

function getPopularity(item) {
  return item.popularity;
}

// We use an object to keep track of multiple values in a single return value.
function addScores({ totalPopularity, itemCount }, popularity) {
  return {
    totalPopularity: totalPopularity + popularity,
    itemCount: itemCount + 1
  };
}

// Calculations
// ---------------------------------------------------------------------------------
const initialInfo = { totalPopularity: 0, itemCount: 0 };
const popularityInfo = victorianSlang
  .filter(isFound)
  .map(getPopularity)
  .reduce(addScores, initialInfo);
const { totalPopularity, itemCount } = popularityInfo;
const averagePopularity = totalPopularity / itemCount;
console.log("Average popularity:", averagePopularity);

4、函数编程式。前面三种相信在工作中是很常用到的,这一种方式熟悉 react 的同学肯定不陌生,我们会根据 api 去使用 compose。如果我们给自己设限,要求模仿这种写法去实现呢?强调下在实际开发中可能并没有什么意义,只是说明了 js 的实现不止一种。

// Helpers
// ----------------------------------------------------------------------------
const filter = p => a => a.filter(p);
const map = f => a => a.map(f);
const prop = k => x => x[k];
const reduce = r => i => a => a.reduce(r, i);
const compose = (...fns) => arg => fns.reduceRight((arg, fn) => fn(arg), arg);

// The blackbird combinator.
// See: https://jrsinclair.com/articles/2019/compose-js-functions-multiple-parameters/
const B1 = f => g => h => x => f(g(x))(h(x));

// Calculations
// ----------------------------------------------------------------------------

// We"ll create a sum function that adds all the items of an array together.
const sum = reduce((a, i) => a + i)(0);

// A function to get the length of an array.
const length = a => a.length;

// A function to divide one number by another.
const div = a => b => a / b;

// We use compose() to piece our function together using the small helpers.
// With compose() you read from the bottom up.
const calcPopularity = compose(
  B1(div)(sum)(length),
  map(prop("popularity")),
  filter(prop("found"))
);

const averagePopularity = calcPopularity(victorianSlang);
console.log("Average popularity:", averagePopularity);

5、只有一次遍历的情况。上面几种方法实际上都用了三次遍历。如果有一种方法能够只遍历一次呢?需要了解一点数学知识如下图,总之就是经过一系列的公式转换可以实现一次遍历。

// Average function
// ----------------------------------------------------------------------------

function averageScores({ avg, n }, slangTermInfo) {
  if (!slangTermInfo.found) {
    return { avg, n };
  }
  return {
    avg: (slangTermInfo.popularity + n * avg) / (n + 1),
    n: n + 1
  };
}

// Calculations
// ----------------------------------------------------------------------------

// Calculate the average and display.
const initialVals = { avg: 0, n: 0 };
const averagePopularity = victorianSlang.reduce(averageScores, initialVals).avg;
console.log("Average popularity:", averagePopularity);

总结:数学学得好,代码写得少

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104841.html

相关文章

  • 我是怎样用函数式JavaScript计算数组均值

    摘要:简单模式记录多个累加值在之前的版本中,我们创建了很多中间变量,。接下来,我们给自己设一个挑战,使用链式操作,将所有的函数调用组合起来,不再使用中间变量。你甚至可以继续简化上述代码,移除不必要的中间变量,让最终的计算代码只有一行。 译者按: 有时候一个算法的直观、简洁、高效是需要作出取舍的。 原文: FUNCTIONAL JAVASCRIPT: FIVE WAYS TO CALCULA...

    renweihub 评论0 收藏0
  • Programming Computer Vision with Python (学习笔记四)

    摘要:上一个笔记主要是讲了的原理,并给出了二维图像降一维的示例代码。当我使用这种方法实现时,程序运行出现错误,发现是对负数开平方根产生了错误,也就是说对协方差矩阵求得的特征值中包含了负数。而能夠用于任意乘矩阵的分解,故适用范围更广。 上一个笔记主要是讲了PCA的原理,并给出了二维图像降一维的示例代码。但还遗留了以下几个问题: 在计算协方差和特征向量的方法上,书上使用的是一种被作者称为com...

    Allen 评论0 收藏0
  • 【数据科学系统学习】Python # 数据分析基本操作[四] 数据规整化和数据聚合与分组运算

    摘要:数据规整化清理转换合并重塑数据聚合与分组运算数据规整化清理转换合并重塑合并数据集可根据一个或多个键将不同中的行链接起来。函数根据样本分位数对数据进行面元划分。字典或,给出待分组轴上的值与分组名之间的对应关系。 本篇内容为整理《利用Python进行数据分析》,博主使用代码为 Python3,部分内容和书本有出入。 在前几篇中我们介绍了 NumPy、pandas、matplotlib 三个...

    The question 评论0 收藏0
  • 爬虫敏感图片识别与过滤,了解一下?

    摘要:爬虫敏感图片的识别与过滤,了解一下需求我们需要识别出敏感作者的头像把皮卡丘换成优雅的。对比哈希不同图片对比的方法,就是对比它们的位哈希中,有多少位不一样汉明距离。 爬虫敏感图片的识别与过滤,了解一下? 需求 我们需要识别出敏感作者的avatar头像,把皮卡丘换成优雅的python。 敏感图片样本属性: showImg(https://ws3.sinaimg.cn/large/006tN...

    linkin 评论0 收藏0
  • Java实现通过日语元音ae发音曲线分类9个发音者

    摘要:需要对个人的日语元音的发音分析,然后根据分析确定名发音者。九个发音者发出两个日本元音先后。其中每块数据中包含的行数为到不等,每行代表着发音者的一个时间帧。 业务理解(Business Understanding) 该业务是分类问题。需要对9个人的日语元音ae的发音分析,然后根据分析确定9名发音者。ae.train文件是训练数据集,ae.test文件是用来测试训练效果的,size_ae...

    lncwwn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<