首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ramda.js换能器:得到的数字数组的平均值

Ramda.js换能器:得到的数字数组的平均值
EN

Stack Overflow用户
提问于 2021-09-15 18:00:51
回答 2查看 140关注 0票数 0

我目前正在学习使用Ramda.js的传感器。(太有趣了,耶!)

我发现this question that描述了如何首先过滤数组,然后使用换能器来总结数组中的值。

我想做些类似的事,但不一样。我有一个具有时间戳的对象数组,我希望平均出时间戳。就像这样:

代码语言:javascript
复制
const createCheckin = ({
  timestamp = Date.now(), // default is now
  startStation = 'foo',
  endStation = 'bar'
} = {}) => ({timestamp, startStation, endStation});

const checkins = [
  createCheckin(),
  createCheckin({ startStation: 'baz' }),
  createCheckin({ timestamp: Date.now() + 100 }), // offset of 100
];

const filterCheckins = R.filter(({ startStation }) => startStation === 'foo');
const mapTimestamps = R.map(({ timestamp }) => timestamp);

const transducer = R.compose(
  filterCheckins,
  mapTimestamps,
);

const average = R.converge(R.divide, [R.sum, R.length]);

R.transduce(transducer, average, 0, checkins);
// Should return something like Date.now() + 50, giving the 100 offset at the top.

当然,上面的average不能工作,因为转换函数的工作方式就像一个约简。

我发现我可以在换能器之后的一步内完成。

代码语言:javascript
复制
const timestamps = R.transduce(transducer,  R.flip(R.append), [], checkins);
average(timestamps);

但是,我认为一定有一种方法可以用迭代器函数(换能器的第二个参数)来实现这一点。你怎么能做到这一点?或者average必须是transducer的一部分(使用compose)?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-15 23:53:27

恐怕这让我觉得很困惑。

我认为换能器是将组合函数的步骤组合在值序列上的一种方法,这样您就只能迭代一次序列。

average在这里没有任何意义。要平均下来,你需要整个收藏。

因此,您可以转换值的过滤和映射。但是你绝对需要分别进行平均化。请注意,filter然后map是一个足够常见的模式,因此有大量的filterMap函数。兰达没有,但这样做很好:

代码语言:javascript
复制
const filterMap = (f, m) => (xs) =>
  xs .flatMap (x => f (x) ? [m (x)] : [])

然后就会像这样使用:

代码语言:javascript
复制
filterMap (
  propEq ('startStation', 'foo'), 
  prop ('timestamp')
) (checkins)

但是对于更复杂的变换序列,换能器当然可以满足要求。

我还建议,如果可能的话,应该使用lift而不是converge。它是一个更标准的FP函数,并且工作在更抽象的数据类型上。在这里,const average = lift (divide) (sum, length)会工作得很好。

票数 1
EN

Stack Overflow用户

发布于 2021-09-18 02:52:27

作为第一步,您可以创建一个简单的类型,以允许合并平均值。这需要对平均项的总数和数量保持一个运行记录。

代码语言:javascript
复制
const Avg = (sum, count) => ({ sum, count })

// creates a new `Avg` from a given value, initilised with a count of 1
Avg.of = n => Avg(n, 1)

// takes two `Avg` types and combines them together
Avg.append = (avg1, avg2) =>
  Avg(avg1.sum + avg2.sum, avg1.count + avg2.count)

这样,我们就可以将注意力转向创建将平均值组合在一起的转换器。

首先,一个简单的帮助函数,它允许将值转换为我们的Avg类型,并将一个约简函数封装为它接收到的第一个值,而不是要求提供一个初始值(平均值不存在一个很好的初始值,因此我们将只使用第一个值)

代码语言:javascript
复制
const mapReduce1 = (map, reduce) =>
  (acc, n) => acc == null ? map(n) : reduce(acc, map(n))

然后,转换器只需要组合Avg值,然后从结果中提取结果平均值。n.b.在转换器在空列表上运行的情况下,结果需要保护null值。

代码语言:javascript
复制
const avgXf = {
  '@@transducer/step': mapReduce1(Avg.of, Avg.append),
  '@@transducer/result': result =>
    result == null ? null : result.sum / result.count
}

然后,您可以将它作为累加器函数传递给transduce,它将产生结果的平均值。

代码语言:javascript
复制
transduce(transducer, avgXf, null, checkins)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69197893

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档