简体   繁体   English

使用Ramda检测序列中的空位?

[英]Detect gaps in a sequence using Ramda?

In ramda.js, how can I detect if there is a gap in a sequence bigger than some value n? 在ramda.js中,如何检测序列中是否存在大于某个值n的间隙?

eg for values that have already been sorted: 例如,对于已经排序的值:

[
    {"name":"bob", loginDate:"2017-10-01"},
    {"name":"bob", loginDate:"2017-10-02"},
    {"name":"bob", loginDate:"2017-10-03"},
    {"name":"bob", loginDate:"2017-10-10"},
]

How would I detect if there has been a gap greater than 7 between the loginDates of any two records? 我如何检测两个记录的loginDate之间是否存在大于7的间隔? But not between the current and the first records - only checking against the previous one. 但不在当前记录与第一条记录之间-仅对照上一条进行检查。 I'm not sure how to compare the current item to the previous item in ramda. 我不确定如何将当前项目与ramda中的上一个项目进行比较。

When wanting to process adjacent values in a list it is often useful to create a list that can be traversed like a sliding window of values using R.aperture . 当想要处理列表中的相邻值时,使用R.aperture创建一个像值的滑动窗口一样可以遍历的列表通常很有用。

A binary function that performs the comparison between the previous and current items of a list can be wrapped in R.apply so that it will accept an array of two elements to compare. 可以在R.apply包装一个执行列表的前一项和当前项之间比较的二进制函数,这样它将接受两个要比较的元素的数组。

To illustrate with your example: 为了说明您的示例:

const maxGap = 1000 * 60 * 60 * 24 * 7 // 7 days in ms
const gtMaxGap = (prev, curr) =>
  maxGap + Date.parse(prev.loginDate) < Date.parse(curr.loginDate)

const anyGapTooLarge = R.pipe(R.aperture(2), R.any(R.apply(gtMaxGap)))

anyGapTooLarge([
  {"name":"bob", loginDate:"2017-10-01"},
  {"name":"bob", loginDate:"2017-10-02"},
  {"name":"bob", loginDate:"2017-10-03"},
  {"name":"bob", loginDate:"2017-10-10"},
]) // false

Another alternative to R.aperture would be to produce the list of adjacent values by using R.zip to zip the list with its own tail. R.aperture另一种选择是通过使用R.zip用自己的尾部压缩列表来生成相邻值的列表。

As a student of functional programming, I worked on this problem. 作为函数编程的学生,我致力于解决这个问题。

I really like the answer by @Scott Christopher; 我真的很喜欢@Scott Christopher的回答; yet I manage work out a different solution before looking at what he did. 但在查看他的工作之前,我设法制定出另一种解决方案。

That approach follows: 该方法如下:

I worked through this a different way. 我以不同的方式工作。 If you want to have the a list of all logins after a given time period and note the difference in time, you could use essentially use reduce then filter for the gap 如果要在给定时间段后获得所有登录的列表,并记下时间差,则可以使用本质上使用reduce然后filter出差距

First, assume the data is contained sorted in a variable called data 首先,假设数据包含在名为data的变量中

example

const logs = [
  {"name":"bob", loginDate:"2017-10-01"},
  {"name":"bob", loginDate:"2017-10-02"},
  {"name":"bob", loginDate:"2017-10-03"},
  {"name":"bob", loginDate:"2017-10-10"},
]

Next, we create a few utility functions and an iterator function 接下来,我们创建一些实用程序函数和一个迭代器函数

const dateDifference = nextDate => initDate => {
  return ( new Date( nextDate ) - new Date( initDate ) )
}
const daysToMs = R.multiply(1000 * 60 * 60 * 24)

const differenceWithPreviousRecordIterator = dateField => differenceField => (acc,val) => {
  const timeDifference = acc.length  
    ? dateDifference
        (val[dateField])
        (R.last(acc)[dateField])
    : 0

  return R.append(
    R.assoc( differenceField, timeDifference, val ),
    acc
  )
}

Now configure the iterator function 现在配置迭代器功能

const iteratorFunc = differenceWithPreviousRecordIterator('loginDate')('difference')

Then get the rows and filter for rows where logins occurred after the desired time 然后获取行并过滤所需时间后发生登录的行

const rowsWithDifference = R.reduce(iteratorFunc,[])(logs)
const sevenDaysAndOlder = R.where({
  difference: R.gte( R.__, daysToMs(7) )
})
const filterForLoginsSevenDaysOrGreater = R.filter( sevenDaysAndOlder )

filterForLoginsSevenDaysOrGreater( rowsWithDifference )
// [ { name: 'bob', loginDate: '2017-10-10', difference: 604800000 } ]

That said, after looking @Scott's approach, a similar effect can be achieved by slightly modifying his solution. 也就是说,在查看@Scott的方法之后,可以通过稍微修改他的解决方案来达到类似的效果。 The modifications being namely that we're looking for a time equal to or greater than the gap instead of just greater than. 修改是,我们正在寻找等于或大于间隔而不是大于的时间。 The other is to simply use filter instead of any 另一种是简单地使用filter而不是any

const maxGap = 1000 * 60 * 60 * 24 * 7 // 7 days in ms
const gtMaxGap = (prev, curr) =>
  maxGap + Date.parse(prev.loginDate) <= Date.parse(curr.loginDate)

const anyGapTooLarge = R.pipe(R.aperture(2), R.filter( R.apply( gtMaxGap ) ))

anyGapTooLarge([
  {"name":"bob", loginDate:"2017-10-01"},
  {"name":"bob", loginDate:"2017-10-02"},
  {"name":"bob", loginDate:"2017-10-03"},
  {"name":"bob", loginDate:"2017-10-10"},
]) // gives pair where login was greater than or equal to maxGap

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

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